@ai-sdk/react 4.0.0-beta.18 → 4.0.0-beta.181
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.
- package/CHANGELOG.md +1306 -0
- package/dist/index.d.ts +123 -3
- package/dist/index.js +806 -90
- package/dist/index.js.map +1 -1
- package/package.json +25 -24
- package/src/chat.react.ts +10 -4
- package/src/index.ts +2 -0
- package/src/mcp-apps/app-frame.tsx +164 -0
- package/src/mcp-apps/app-renderer.tsx +98 -0
- package/src/mcp-apps/bridge.ts +408 -0
- package/src/mcp-apps/index.ts +8 -0
- package/src/mcp-apps/sandbox.ts +74 -0
- package/src/mcp-apps/types.ts +105 -0
- package/src/mcp-apps/utils.ts +84 -0
- package/src/use-chat.ts +1 -6
- package/src/use-completion.ts +2 -2
- package/src/use-object.ts +11 -6
- package/src/use-realtime.ts +252 -0
- package/dist/index.d.mts +0 -178
- package/dist/index.mjs +0 -506
- package/dist/index.mjs.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,31 +1,3 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __create = Object.create;
|
|
3
|
-
var __defProp = Object.defineProperty;
|
|
4
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
-
var __export = (target, all) => {
|
|
9
|
-
for (var name in all)
|
|
10
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
-
};
|
|
12
|
-
var __copyProps = (to, from, except, desc) => {
|
|
13
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
-
for (let key of __getOwnPropNames(from))
|
|
15
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
-
}
|
|
18
|
-
return to;
|
|
19
|
-
};
|
|
20
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
-
mod
|
|
27
|
-
));
|
|
28
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
1
|
var __accessCheck = (obj, member, msg) => {
|
|
30
2
|
if (!member.has(obj))
|
|
31
3
|
throw TypeError("Cannot " + msg);
|
|
@@ -45,26 +17,18 @@ var __privateSet = (obj, member, value, setter) => {
|
|
|
45
17
|
return value;
|
|
46
18
|
};
|
|
47
19
|
|
|
48
|
-
// src/index.ts
|
|
49
|
-
var src_exports = {};
|
|
50
|
-
__export(src_exports, {
|
|
51
|
-
Chat: () => Chat,
|
|
52
|
-
experimental_useObject: () => experimental_useObject,
|
|
53
|
-
useChat: () => useChat,
|
|
54
|
-
useCompletion: () => useCompletion
|
|
55
|
-
});
|
|
56
|
-
module.exports = __toCommonJS(src_exports);
|
|
57
|
-
|
|
58
20
|
// src/use-chat.ts
|
|
59
|
-
|
|
21
|
+
import { useCallback, useEffect, useRef, useSyncExternalStore } from "react";
|
|
60
22
|
|
|
61
23
|
// src/chat.react.ts
|
|
62
|
-
|
|
24
|
+
import {
|
|
25
|
+
AbstractChat
|
|
26
|
+
} from "ai";
|
|
63
27
|
|
|
64
28
|
// src/throttle.ts
|
|
65
|
-
|
|
29
|
+
import throttleFunction from "throttleit";
|
|
66
30
|
function throttle(fn, waitMs) {
|
|
67
|
-
return waitMs != null ? (
|
|
31
|
+
return waitMs != null ? throttleFunction(fn, waitMs) : fn;
|
|
68
32
|
}
|
|
69
33
|
|
|
70
34
|
// src/chat.react.ts
|
|
@@ -157,7 +121,7 @@ _callMessagesCallbacks = new WeakMap();
|
|
|
157
121
|
_callStatusCallbacks = new WeakMap();
|
|
158
122
|
_callErrorCallbacks = new WeakMap();
|
|
159
123
|
var _state;
|
|
160
|
-
var Chat = class extends
|
|
124
|
+
var Chat = class extends AbstractChat {
|
|
161
125
|
constructor({ messages, ...init }) {
|
|
162
126
|
const state = new ReactChatState(messages);
|
|
163
127
|
super({ ...init, state });
|
|
@@ -176,7 +140,7 @@ function useChat({
|
|
|
176
140
|
resume = false,
|
|
177
141
|
...options
|
|
178
142
|
} = {}) {
|
|
179
|
-
const callbacksRef =
|
|
143
|
+
const callbacksRef = useRef(
|
|
180
144
|
!("chat" in options) ? {
|
|
181
145
|
onToolCall: options.onToolCall,
|
|
182
146
|
onData: options.onData,
|
|
@@ -217,35 +181,35 @@ function useChat({
|
|
|
217
181
|
return (_c = (_b = (_a = callbacksRef.current).sendAutomaticallyWhen) == null ? void 0 : _b.call(_a, arg)) != null ? _c : false;
|
|
218
182
|
}
|
|
219
183
|
};
|
|
220
|
-
const chatRef =
|
|
184
|
+
const chatRef = useRef(
|
|
221
185
|
"chat" in options ? options.chat : new Chat(optionsWithCallbacks)
|
|
222
186
|
);
|
|
223
187
|
const shouldRecreateChat = "chat" in options && options.chat !== chatRef.current || "id" in options && chatRef.current.id !== options.id;
|
|
224
188
|
if (shouldRecreateChat) {
|
|
225
189
|
chatRef.current = "chat" in options ? options.chat : new Chat(optionsWithCallbacks);
|
|
226
190
|
}
|
|
227
|
-
const subscribeToMessages =
|
|
191
|
+
const subscribeToMessages = useCallback(
|
|
228
192
|
(update) => chatRef.current["~registerMessagesCallback"](update, throttleWaitMs),
|
|
229
193
|
// `chatRef.current.id` is required to trigger re-subscription when the chat ID changes
|
|
230
194
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
231
195
|
[throttleWaitMs, chatRef.current.id]
|
|
232
196
|
);
|
|
233
|
-
const messages =
|
|
197
|
+
const messages = useSyncExternalStore(
|
|
234
198
|
subscribeToMessages,
|
|
235
199
|
() => chatRef.current.messages,
|
|
236
200
|
() => chatRef.current.messages
|
|
237
201
|
);
|
|
238
|
-
const status =
|
|
202
|
+
const status = useSyncExternalStore(
|
|
239
203
|
chatRef.current["~registerStatusCallback"],
|
|
240
204
|
() => chatRef.current.status,
|
|
241
205
|
() => chatRef.current.status
|
|
242
206
|
);
|
|
243
|
-
const error =
|
|
207
|
+
const error = useSyncExternalStore(
|
|
244
208
|
chatRef.current["~registerErrorCallback"],
|
|
245
209
|
() => chatRef.current.error,
|
|
246
210
|
() => chatRef.current.error
|
|
247
211
|
);
|
|
248
|
-
const setMessages =
|
|
212
|
+
const setMessages = useCallback(
|
|
249
213
|
(messagesParam) => {
|
|
250
214
|
if (typeof messagesParam === "function") {
|
|
251
215
|
messagesParam = messagesParam(chatRef.current.messages);
|
|
@@ -254,7 +218,7 @@ function useChat({
|
|
|
254
218
|
},
|
|
255
219
|
[chatRef]
|
|
256
220
|
);
|
|
257
|
-
|
|
221
|
+
useEffect(() => {
|
|
258
222
|
if (resume) {
|
|
259
223
|
chatRef.current.resumeStream();
|
|
260
224
|
}
|
|
@@ -280,9 +244,11 @@ function useChat({
|
|
|
280
244
|
}
|
|
281
245
|
|
|
282
246
|
// src/use-completion.ts
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
247
|
+
import {
|
|
248
|
+
callCompletionApi
|
|
249
|
+
} from "ai";
|
|
250
|
+
import { useCallback as useCallback2, useEffect as useEffect2, useId, useRef as useRef2, useState } from "react";
|
|
251
|
+
import useSWR from "swr";
|
|
286
252
|
function useCompletion({
|
|
287
253
|
api = "/api/completion",
|
|
288
254
|
id,
|
|
@@ -297,32 +263,32 @@ function useCompletion({
|
|
|
297
263
|
onError,
|
|
298
264
|
experimental_throttle: throttleWaitMs
|
|
299
265
|
} = {}) {
|
|
300
|
-
const hookId =
|
|
266
|
+
const hookId = useId();
|
|
301
267
|
const completionId = id || hookId;
|
|
302
|
-
const { data, mutate } = (
|
|
268
|
+
const { data, mutate } = useSWR([api, completionId], null, {
|
|
303
269
|
fallbackData: initialCompletion
|
|
304
270
|
});
|
|
305
|
-
const { data: isLoading = false, mutate: mutateLoading } = (
|
|
271
|
+
const { data: isLoading = false, mutate: mutateLoading } = useSWR(
|
|
306
272
|
[completionId, "loading"],
|
|
307
273
|
null
|
|
308
274
|
);
|
|
309
|
-
const [error, setError] =
|
|
275
|
+
const [error, setError] = useState(void 0);
|
|
310
276
|
const completion = data;
|
|
311
|
-
const [abortController, setAbortController] =
|
|
312
|
-
const extraMetadataRef = (
|
|
277
|
+
const [abortController, setAbortController] = useState(null);
|
|
278
|
+
const extraMetadataRef = useRef2({
|
|
313
279
|
credentials,
|
|
314
280
|
headers,
|
|
315
281
|
body
|
|
316
282
|
});
|
|
317
|
-
(
|
|
283
|
+
useEffect2(() => {
|
|
318
284
|
extraMetadataRef.current = {
|
|
319
285
|
credentials,
|
|
320
286
|
headers,
|
|
321
287
|
body
|
|
322
288
|
};
|
|
323
289
|
}, [credentials, headers, body]);
|
|
324
|
-
const triggerRequest = (
|
|
325
|
-
async (prompt, options) =>
|
|
290
|
+
const triggerRequest = useCallback2(
|
|
291
|
+
async (prompt, options) => callCompletionApi({
|
|
326
292
|
api,
|
|
327
293
|
prompt,
|
|
328
294
|
credentials: extraMetadataRef.current.credentials,
|
|
@@ -358,26 +324,26 @@ function useCompletion({
|
|
|
358
324
|
throttleWaitMs
|
|
359
325
|
]
|
|
360
326
|
);
|
|
361
|
-
const stop = (
|
|
327
|
+
const stop = useCallback2(() => {
|
|
362
328
|
if (abortController) {
|
|
363
329
|
abortController.abort();
|
|
364
330
|
setAbortController(null);
|
|
365
331
|
}
|
|
366
332
|
}, [abortController]);
|
|
367
|
-
const setCompletion = (
|
|
333
|
+
const setCompletion = useCallback2(
|
|
368
334
|
(completion2) => {
|
|
369
335
|
mutate(completion2, false);
|
|
370
336
|
},
|
|
371
337
|
[mutate]
|
|
372
338
|
);
|
|
373
|
-
const complete = (
|
|
339
|
+
const complete = useCallback2(
|
|
374
340
|
async (prompt, options) => {
|
|
375
341
|
return triggerRequest(prompt, options);
|
|
376
342
|
},
|
|
377
343
|
[triggerRequest]
|
|
378
344
|
);
|
|
379
|
-
const [input, setInput] =
|
|
380
|
-
const handleSubmit = (
|
|
345
|
+
const [input, setInput] = useState(initialInput);
|
|
346
|
+
const handleSubmit = useCallback2(
|
|
381
347
|
(event) => {
|
|
382
348
|
var _a;
|
|
383
349
|
(_a = event == null ? void 0 : event.preventDefault) == null ? void 0 : _a.call(event);
|
|
@@ -385,7 +351,7 @@ function useCompletion({
|
|
|
385
351
|
},
|
|
386
352
|
[input, complete]
|
|
387
353
|
);
|
|
388
|
-
const handleInputChange = (
|
|
354
|
+
const handleInputChange = useCallback2(
|
|
389
355
|
(e) => {
|
|
390
356
|
setInput(e.target.value);
|
|
391
357
|
},
|
|
@@ -406,10 +372,19 @@ function useCompletion({
|
|
|
406
372
|
}
|
|
407
373
|
|
|
408
374
|
// src/use-object.ts
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
375
|
+
import {
|
|
376
|
+
isAbortError,
|
|
377
|
+
resolve,
|
|
378
|
+
normalizeHeaders,
|
|
379
|
+
safeValidateTypes
|
|
380
|
+
} from "@ai-sdk/provider-utils";
|
|
381
|
+
import {
|
|
382
|
+
asSchema,
|
|
383
|
+
isDeepEqualData,
|
|
384
|
+
parsePartialJson
|
|
385
|
+
} from "ai";
|
|
386
|
+
import { useCallback as useCallback3, useId as useId2, useRef as useRef3, useState as useState2 } from "react";
|
|
387
|
+
import useSWR2 from "swr";
|
|
413
388
|
var getOriginalFetch = () => fetch;
|
|
414
389
|
function useObject({
|
|
415
390
|
api,
|
|
@@ -423,21 +398,21 @@ function useObject({
|
|
|
423
398
|
headers,
|
|
424
399
|
credentials
|
|
425
400
|
}) {
|
|
426
|
-
const hookId = (
|
|
401
|
+
const hookId = useId2();
|
|
427
402
|
const completionId = id != null ? id : hookId;
|
|
428
|
-
const { data, mutate } = (
|
|
403
|
+
const { data, mutate } = useSWR2(
|
|
429
404
|
[api, completionId],
|
|
430
405
|
null,
|
|
431
406
|
{ fallbackData: initialValue }
|
|
432
407
|
);
|
|
433
|
-
const [error, setError] = (
|
|
434
|
-
const [isLoading, setIsLoading] = (
|
|
435
|
-
const abortControllerRef = (
|
|
436
|
-
const stop = (
|
|
408
|
+
const [error, setError] = useState2(void 0);
|
|
409
|
+
const [isLoading, setIsLoading] = useState2(false);
|
|
410
|
+
const abortControllerRef = useRef3(null);
|
|
411
|
+
const stop = useCallback3(() => {
|
|
437
412
|
var _a;
|
|
438
413
|
try {
|
|
439
414
|
(_a = abortControllerRef.current) == null ? void 0 : _a.abort();
|
|
440
|
-
} catch (
|
|
415
|
+
} catch (e) {
|
|
441
416
|
} finally {
|
|
442
417
|
setIsLoading(false);
|
|
443
418
|
abortControllerRef.current = null;
|
|
@@ -450,13 +425,13 @@ function useObject({
|
|
|
450
425
|
setIsLoading(true);
|
|
451
426
|
const abortController = new AbortController();
|
|
452
427
|
abortControllerRef.current = abortController;
|
|
453
|
-
const resolvedHeaders = await
|
|
428
|
+
const resolvedHeaders = await resolve(headers);
|
|
454
429
|
const actualFetch = fetch2 != null ? fetch2 : getOriginalFetch();
|
|
455
430
|
const response = await actualFetch(api, {
|
|
456
431
|
method: "POST",
|
|
457
432
|
headers: {
|
|
458
433
|
"Content-Type": "application/json",
|
|
459
|
-
...
|
|
434
|
+
...normalizeHeaders(resolvedHeaders)
|
|
460
435
|
},
|
|
461
436
|
credentials,
|
|
462
437
|
signal: abortController.signal,
|
|
@@ -476,9 +451,9 @@ function useObject({
|
|
|
476
451
|
new WritableStream({
|
|
477
452
|
async write(chunk) {
|
|
478
453
|
accumulatedText += chunk;
|
|
479
|
-
const { value } = await
|
|
454
|
+
const { value } = await parsePartialJson(accumulatedText);
|
|
480
455
|
const currentObject = value;
|
|
481
|
-
if (!
|
|
456
|
+
if (!isDeepEqualData(latestObject, currentObject)) {
|
|
482
457
|
latestObject = currentObject;
|
|
483
458
|
mutate(currentObject);
|
|
484
459
|
}
|
|
@@ -487,9 +462,9 @@ function useObject({
|
|
|
487
462
|
setIsLoading(false);
|
|
488
463
|
abortControllerRef.current = null;
|
|
489
464
|
if (onFinish != null) {
|
|
490
|
-
const validationResult = await
|
|
465
|
+
const validationResult = await safeValidateTypes({
|
|
491
466
|
value: latestObject,
|
|
492
|
-
schema:
|
|
467
|
+
schema: asSchema(schema)
|
|
493
468
|
});
|
|
494
469
|
onFinish(
|
|
495
470
|
validationResult.success ? { object: validationResult.value, error: void 0 } : { object: void 0, error: validationResult.error }
|
|
@@ -499,7 +474,7 @@ function useObject({
|
|
|
499
474
|
})
|
|
500
475
|
);
|
|
501
476
|
} catch (error2) {
|
|
502
|
-
if (
|
|
477
|
+
if (isAbortError(error2)) {
|
|
503
478
|
return;
|
|
504
479
|
}
|
|
505
480
|
if (onError && error2 instanceof Error) {
|
|
@@ -528,11 +503,752 @@ function useObject({
|
|
|
528
503
|
};
|
|
529
504
|
}
|
|
530
505
|
var experimental_useObject = useObject;
|
|
531
|
-
|
|
532
|
-
|
|
506
|
+
|
|
507
|
+
// src/use-realtime.ts
|
|
508
|
+
import {
|
|
509
|
+
Experimental_AbstractRealtimeSession as AbstractRealtimeSession
|
|
510
|
+
} from "ai";
|
|
511
|
+
import { useCallback as useCallback4, useEffect as useEffect3, useRef as useRef4, useSyncExternalStore as useSyncExternalStore2 } from "react";
|
|
512
|
+
function getRealtimeStoreKey(options) {
|
|
513
|
+
return {
|
|
514
|
+
model: options.model,
|
|
515
|
+
token: options.api.token,
|
|
516
|
+
sessionConfig: options.sessionConfig,
|
|
517
|
+
sampleRate: options.sampleRate,
|
|
518
|
+
maxEvents: options.maxEvents
|
|
519
|
+
};
|
|
520
|
+
}
|
|
521
|
+
function shouldCreateRealtimeStore(currentKey, nextOptions) {
|
|
522
|
+
return currentKey.model !== nextOptions.model || currentKey.token !== nextOptions.api.token || currentKey.sessionConfig !== nextOptions.sessionConfig || currentKey.sampleRate !== nextOptions.sampleRate || currentKey.maxEvents !== nextOptions.maxEvents;
|
|
523
|
+
}
|
|
524
|
+
var RealtimeStore = class extends AbstractRealtimeSession {
|
|
525
|
+
constructor() {
|
|
526
|
+
super(...arguments);
|
|
527
|
+
this.state = {
|
|
528
|
+
status: "disconnected",
|
|
529
|
+
messages: [],
|
|
530
|
+
events: [],
|
|
531
|
+
isCapturing: false,
|
|
532
|
+
isPlaying: false
|
|
533
|
+
};
|
|
534
|
+
this.callbacks = {
|
|
535
|
+
status: /* @__PURE__ */ new Set(),
|
|
536
|
+
messages: /* @__PURE__ */ new Set(),
|
|
537
|
+
events: /* @__PURE__ */ new Set(),
|
|
538
|
+
isCapturing: /* @__PURE__ */ new Set(),
|
|
539
|
+
isPlaying: /* @__PURE__ */ new Set()
|
|
540
|
+
};
|
|
541
|
+
}
|
|
542
|
+
get status() {
|
|
543
|
+
return this.state.status;
|
|
544
|
+
}
|
|
545
|
+
get messages() {
|
|
546
|
+
return this.state.messages;
|
|
547
|
+
}
|
|
548
|
+
get events() {
|
|
549
|
+
return this.state.events;
|
|
550
|
+
}
|
|
551
|
+
get isCapturing() {
|
|
552
|
+
return this.state.isCapturing;
|
|
553
|
+
}
|
|
554
|
+
get isPlaying() {
|
|
555
|
+
return this.state.isPlaying;
|
|
556
|
+
}
|
|
557
|
+
subscribe(key, onChange) {
|
|
558
|
+
this.callbacks[key].add(onChange);
|
|
559
|
+
return () => {
|
|
560
|
+
this.callbacks[key].delete(onChange);
|
|
561
|
+
};
|
|
562
|
+
}
|
|
563
|
+
setState(key, value) {
|
|
564
|
+
this.state = { ...this.state, [key]: value };
|
|
565
|
+
this.callbacks[key].forEach((callback) => callback());
|
|
566
|
+
}
|
|
567
|
+
pushMessage(message) {
|
|
568
|
+
this.state = {
|
|
569
|
+
...this.state,
|
|
570
|
+
messages: [...this.state.messages, message]
|
|
571
|
+
};
|
|
572
|
+
this.callbacks.messages.forEach((callback) => callback());
|
|
573
|
+
}
|
|
574
|
+
updateMessages(updater) {
|
|
575
|
+
this.state = {
|
|
576
|
+
...this.state,
|
|
577
|
+
messages: updater(this.state.messages)
|
|
578
|
+
};
|
|
579
|
+
this.callbacks.messages.forEach((callback) => callback());
|
|
580
|
+
}
|
|
581
|
+
pushEvent(event) {
|
|
582
|
+
const nextEvents = [...this.state.events, event];
|
|
583
|
+
this.state = {
|
|
584
|
+
...this.state,
|
|
585
|
+
events: nextEvents.length > this.maxEvents ? nextEvents.slice(-this.maxEvents) : nextEvents
|
|
586
|
+
};
|
|
587
|
+
this.callbacks.events.forEach((callback) => callback());
|
|
588
|
+
}
|
|
589
|
+
};
|
|
590
|
+
function useRealtime(options) {
|
|
591
|
+
const callbacksRef = useRef4({
|
|
592
|
+
onToolCall: options.onToolCall,
|
|
593
|
+
onEvent: options.onEvent,
|
|
594
|
+
onError: options.onError
|
|
595
|
+
});
|
|
596
|
+
callbacksRef.current = {
|
|
597
|
+
onToolCall: options.onToolCall,
|
|
598
|
+
onEvent: options.onEvent,
|
|
599
|
+
onError: options.onError
|
|
600
|
+
};
|
|
601
|
+
const realtimeRef = useRef4(null);
|
|
602
|
+
let realtimeEntry = realtimeRef.current;
|
|
603
|
+
if (realtimeEntry == null || shouldCreateRealtimeStore(realtimeEntry.key, options)) {
|
|
604
|
+
realtimeEntry = {
|
|
605
|
+
store: new RealtimeStore({
|
|
606
|
+
...options,
|
|
607
|
+
onToolCall: (...args) => {
|
|
608
|
+
var _a, _b;
|
|
609
|
+
return (_b = (_a = callbacksRef.current).onToolCall) == null ? void 0 : _b.call(_a, ...args);
|
|
610
|
+
},
|
|
611
|
+
onEvent: (...args) => {
|
|
612
|
+
var _a, _b;
|
|
613
|
+
return (_b = (_a = callbacksRef.current).onEvent) == null ? void 0 : _b.call(_a, ...args);
|
|
614
|
+
},
|
|
615
|
+
onError: (...args) => {
|
|
616
|
+
var _a, _b;
|
|
617
|
+
return (_b = (_a = callbacksRef.current).onError) == null ? void 0 : _b.call(_a, ...args);
|
|
618
|
+
}
|
|
619
|
+
}),
|
|
620
|
+
key: getRealtimeStoreKey(options)
|
|
621
|
+
};
|
|
622
|
+
realtimeRef.current = realtimeEntry;
|
|
623
|
+
} else {
|
|
624
|
+
realtimeEntry.key = getRealtimeStoreKey(options);
|
|
625
|
+
}
|
|
626
|
+
const rt = realtimeEntry.store;
|
|
627
|
+
const status = useSyncExternalStore2(
|
|
628
|
+
useCallback4((cb) => rt.subscribe("status", cb), [rt]),
|
|
629
|
+
() => rt.status,
|
|
630
|
+
() => rt.status
|
|
631
|
+
);
|
|
632
|
+
const messages = useSyncExternalStore2(
|
|
633
|
+
useCallback4((cb) => rt.subscribe("messages", cb), [rt]),
|
|
634
|
+
() => rt.messages,
|
|
635
|
+
() => rt.messages
|
|
636
|
+
);
|
|
637
|
+
const events = useSyncExternalStore2(
|
|
638
|
+
useCallback4((cb) => rt.subscribe("events", cb), [rt]),
|
|
639
|
+
() => rt.events,
|
|
640
|
+
() => rt.events
|
|
641
|
+
);
|
|
642
|
+
const isCapturing = useSyncExternalStore2(
|
|
643
|
+
useCallback4((cb) => rt.subscribe("isCapturing", cb), [rt]),
|
|
644
|
+
() => rt.isCapturing,
|
|
645
|
+
() => rt.isCapturing
|
|
646
|
+
);
|
|
647
|
+
const isPlaying = useSyncExternalStore2(
|
|
648
|
+
useCallback4((cb) => rt.subscribe("isPlaying", cb), [rt]),
|
|
649
|
+
() => rt.isPlaying,
|
|
650
|
+
() => rt.isPlaying
|
|
651
|
+
);
|
|
652
|
+
useEffect3(() => {
|
|
653
|
+
return () => rt.dispose();
|
|
654
|
+
}, [rt]);
|
|
655
|
+
return {
|
|
656
|
+
status,
|
|
657
|
+
messages,
|
|
658
|
+
events,
|
|
659
|
+
isCapturing,
|
|
660
|
+
isPlaying,
|
|
661
|
+
connect: rt.connect.bind(rt),
|
|
662
|
+
disconnect: rt.disconnect.bind(rt),
|
|
663
|
+
addToolOutput: rt.addToolOutput.bind(rt),
|
|
664
|
+
sendEvent: rt.sendEvent.bind(rt),
|
|
665
|
+
sendTextMessage: rt.sendTextMessage.bind(rt),
|
|
666
|
+
sendAudio: rt.sendAudio.bind(rt),
|
|
667
|
+
commitAudio: rt.commitAudio.bind(rt),
|
|
668
|
+
clearAudioBuffer: rt.clearAudioBuffer.bind(rt),
|
|
669
|
+
requestResponse: rt.requestResponse.bind(rt),
|
|
670
|
+
cancelResponse: rt.cancelResponse.bind(rt),
|
|
671
|
+
startAudioCapture: rt.startAudioCapture.bind(rt),
|
|
672
|
+
stopAudioCapture: rt.stopAudioCapture.bind(rt),
|
|
673
|
+
stopPlayback: rt.stopPlayback.bind(rt)
|
|
674
|
+
};
|
|
675
|
+
}
|
|
676
|
+
var experimental_useRealtime = useRealtime;
|
|
677
|
+
|
|
678
|
+
// src/mcp-apps/app-renderer.tsx
|
|
679
|
+
import { useEffect as useEffect5, useState as useState3 } from "react";
|
|
680
|
+
|
|
681
|
+
// src/mcp-apps/app-frame.tsx
|
|
682
|
+
import { useEffect as useEffect4, useMemo, useRef as useRef5 } from "react";
|
|
683
|
+
|
|
684
|
+
// src/mcp-apps/bridge.ts
|
|
685
|
+
import { isJSONObject } from "@ai-sdk/provider";
|
|
686
|
+
var MCP_APP_PROTOCOL_VERSION = "2026-01-26";
|
|
687
|
+
function isJsonRpcMessage(value) {
|
|
688
|
+
return value != null && typeof value === "object" && !Array.isArray(value) && "jsonrpc" in value && value.jsonrpc === "2.0";
|
|
689
|
+
}
|
|
690
|
+
function isRequest(message) {
|
|
691
|
+
return "method" in message && "id" in message;
|
|
692
|
+
}
|
|
693
|
+
function isNotification(message) {
|
|
694
|
+
return "method" in message && !("id" in message);
|
|
695
|
+
}
|
|
696
|
+
function toError(error) {
|
|
697
|
+
return error instanceof Error ? error : new Error(String(error));
|
|
698
|
+
}
|
|
699
|
+
function assertToolCallParams(params) {
|
|
700
|
+
if (!isJSONObject(params) || typeof params.name !== "string") {
|
|
701
|
+
throw new Error("Invalid tools/call params");
|
|
702
|
+
}
|
|
703
|
+
return {
|
|
704
|
+
name: params.name,
|
|
705
|
+
arguments: isJSONObject(params.arguments) ? params.arguments : void 0
|
|
706
|
+
};
|
|
707
|
+
}
|
|
708
|
+
var MCPAppBridge = class {
|
|
709
|
+
constructor({
|
|
710
|
+
targetWindow,
|
|
711
|
+
targetOrigin = "*",
|
|
712
|
+
handlers = {},
|
|
713
|
+
hostInfo = { name: "ai-sdk-react", version: "1.0.0" },
|
|
714
|
+
hostContext = { displayMode: "inline" }
|
|
715
|
+
}) {
|
|
716
|
+
this.initialized = false;
|
|
717
|
+
this.pendingNotifications = [];
|
|
718
|
+
this.nextRequestId = 0;
|
|
719
|
+
this.pendingResponses = /* @__PURE__ */ new Map();
|
|
720
|
+
this.targetWindow = targetWindow;
|
|
721
|
+
this.targetOrigin = targetOrigin;
|
|
722
|
+
this.handlers = handlers;
|
|
723
|
+
this.hostInfo = hostInfo;
|
|
724
|
+
this.hostContext = hostContext;
|
|
725
|
+
}
|
|
726
|
+
/**
|
|
727
|
+
* Replaces the callbacks used to serve iframe requests.
|
|
728
|
+
*/
|
|
729
|
+
setHandlers(handlers) {
|
|
730
|
+
this.handlers = handlers;
|
|
731
|
+
}
|
|
732
|
+
/**
|
|
733
|
+
* Updates host context and notifies the iframe after initialization.
|
|
734
|
+
*
|
|
735
|
+
* @example
|
|
736
|
+
* ```ts
|
|
737
|
+
* bridge.setHostContext({ theme: 'dark', displayMode: 'inline' });
|
|
738
|
+
* ```
|
|
739
|
+
*/
|
|
740
|
+
setHostContext(hostContext) {
|
|
741
|
+
this.hostContext = hostContext;
|
|
742
|
+
this.sendNotification({
|
|
743
|
+
method: "ui/notifications/host-context-changed",
|
|
744
|
+
params: hostContext
|
|
745
|
+
});
|
|
746
|
+
}
|
|
747
|
+
/**
|
|
748
|
+
* Processes one `message` event from the sandbox proxy iframe.
|
|
749
|
+
*/
|
|
750
|
+
handleMessage(event) {
|
|
751
|
+
if (event.source !== this.targetWindow || !isJsonRpcMessage(event.data)) {
|
|
752
|
+
return;
|
|
753
|
+
}
|
|
754
|
+
const message = event.data;
|
|
755
|
+
if ("result" in message || "error" in message) {
|
|
756
|
+
this.handleResponse(message);
|
|
757
|
+
return;
|
|
758
|
+
}
|
|
759
|
+
if (isRequest(message)) {
|
|
760
|
+
void this.handleRequest(message);
|
|
761
|
+
return;
|
|
762
|
+
}
|
|
763
|
+
if (isNotification(message)) {
|
|
764
|
+
this.handleNotification(message);
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
/**
|
|
768
|
+
* Sends app HTML and sandbox settings to the sandbox proxy.
|
|
769
|
+
*/
|
|
770
|
+
sendSandboxResourceReady(params) {
|
|
771
|
+
this.post({
|
|
772
|
+
jsonrpc: "2.0",
|
|
773
|
+
method: "ui/notifications/sandbox-resource-ready",
|
|
774
|
+
params
|
|
775
|
+
});
|
|
776
|
+
}
|
|
777
|
+
/**
|
|
778
|
+
* Sends final tool arguments to the MCP App.
|
|
779
|
+
*/
|
|
780
|
+
sendToolInput(input) {
|
|
781
|
+
this.sendNotification({
|
|
782
|
+
method: "ui/notifications/tool-input",
|
|
783
|
+
params: { arguments: input }
|
|
784
|
+
});
|
|
785
|
+
}
|
|
786
|
+
/**
|
|
787
|
+
* Sends a completed MCP tool result to the MCP App.
|
|
788
|
+
*/
|
|
789
|
+
sendToolResult(result) {
|
|
790
|
+
this.sendNotification({
|
|
791
|
+
method: "ui/notifications/tool-result",
|
|
792
|
+
params: result
|
|
793
|
+
});
|
|
794
|
+
}
|
|
795
|
+
/**
|
|
796
|
+
* Notifies the MCP App that the related tool call was cancelled.
|
|
797
|
+
*/
|
|
798
|
+
sendToolCancelled(reason) {
|
|
799
|
+
this.sendNotification({
|
|
800
|
+
method: "ui/notifications/tool-cancelled",
|
|
801
|
+
params: reason != null ? { reason } : {}
|
|
802
|
+
});
|
|
803
|
+
}
|
|
804
|
+
/**
|
|
805
|
+
* Requests graceful teardown before the host removes the iframe.
|
|
806
|
+
*/
|
|
807
|
+
teardownResource() {
|
|
808
|
+
return this.request("ui/resource-teardown", {});
|
|
809
|
+
}
|
|
810
|
+
/**
|
|
811
|
+
* Rejects pending bridge requests and clears queued notifications.
|
|
812
|
+
*/
|
|
813
|
+
close() {
|
|
814
|
+
for (const pending of this.pendingResponses.values()) {
|
|
815
|
+
pending.reject(new Error("MCP App bridge closed"));
|
|
816
|
+
}
|
|
817
|
+
this.pendingResponses.clear();
|
|
818
|
+
this.pendingNotifications = [];
|
|
819
|
+
}
|
|
820
|
+
/**
|
|
821
|
+
* Resolves or rejects a host-initiated request when the iframe responds.
|
|
822
|
+
*/
|
|
823
|
+
handleResponse(response) {
|
|
824
|
+
const pending = this.pendingResponses.get(response.id);
|
|
825
|
+
if (pending == null) {
|
|
826
|
+
return;
|
|
827
|
+
}
|
|
828
|
+
this.pendingResponses.delete(response.id);
|
|
829
|
+
if (response.error != null) {
|
|
830
|
+
pending.reject(new Error(response.error.message));
|
|
831
|
+
} else {
|
|
832
|
+
pending.resolve(response.result);
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
/**
|
|
836
|
+
* Runs a handler for an iframe request and posts the JSON-RPC response.
|
|
837
|
+
*/
|
|
838
|
+
async handleRequest(request) {
|
|
839
|
+
var _a, _b;
|
|
840
|
+
try {
|
|
841
|
+
const result = await this.getRequestResult(request);
|
|
842
|
+
this.post({ jsonrpc: "2.0", id: request.id, result });
|
|
843
|
+
} catch (error) {
|
|
844
|
+
const normalizedError = toError(error);
|
|
845
|
+
(_b = (_a = this.handlers).onError) == null ? void 0 : _b.call(_a, normalizedError);
|
|
846
|
+
this.post({
|
|
847
|
+
jsonrpc: "2.0",
|
|
848
|
+
id: request.id,
|
|
849
|
+
error: { code: -32603, message: normalizedError.message }
|
|
850
|
+
});
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
/**
|
|
854
|
+
* Maps supported iframe request methods to host callbacks.
|
|
855
|
+
*/
|
|
856
|
+
async getRequestResult(request) {
|
|
857
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
|
|
858
|
+
switch (request.method) {
|
|
859
|
+
case "ui/initialize":
|
|
860
|
+
return {
|
|
861
|
+
protocolVersion: MCP_APP_PROTOCOL_VERSION,
|
|
862
|
+
hostCapabilities: {
|
|
863
|
+
...this.handlers.callTool != null ? { serverTools: {} } : {},
|
|
864
|
+
...this.handlers.readResource != null ? { serverResources: {} } : {},
|
|
865
|
+
...this.handlers.onLog != null ? { logging: {} } : {}
|
|
866
|
+
},
|
|
867
|
+
hostInfo: this.hostInfo,
|
|
868
|
+
hostContext: this.hostContext
|
|
869
|
+
};
|
|
870
|
+
case "tools/call": {
|
|
871
|
+
if (this.handlers.callTool == null) {
|
|
872
|
+
throw new Error("No tools/call handler configured");
|
|
873
|
+
}
|
|
874
|
+
const params = assertToolCallParams(request.params);
|
|
875
|
+
if (this.handlers.allowedTools == null || !this.handlers.allowedTools.includes(params.name)) {
|
|
876
|
+
throw new Error(`Tool is not app-visible: ${params.name}`);
|
|
877
|
+
}
|
|
878
|
+
return this.handlers.callTool(params);
|
|
879
|
+
}
|
|
880
|
+
case "resources/read":
|
|
881
|
+
if (this.handlers.readResource == null) {
|
|
882
|
+
throw new Error("No resources/read handler configured");
|
|
883
|
+
}
|
|
884
|
+
return this.handlers.readResource(request.params);
|
|
885
|
+
case "resources/list":
|
|
886
|
+
if (this.handlers.listResources == null) {
|
|
887
|
+
throw new Error("No resources/list handler configured");
|
|
888
|
+
}
|
|
889
|
+
return this.handlers.listResources(request.params);
|
|
890
|
+
case "ui/open-link":
|
|
891
|
+
if (this.handlers.openLink == null) {
|
|
892
|
+
throw new Error("No ui/open-link handler configured");
|
|
893
|
+
}
|
|
894
|
+
return this.handlers.openLink(request.params);
|
|
895
|
+
case "ui/message":
|
|
896
|
+
return (_c = (_b = (_a = this.handlers).sendMessage) == null ? void 0 : _b.call(_a, request.params)) != null ? _c : {};
|
|
897
|
+
case "ui/update-model-context":
|
|
898
|
+
return (_f = (_e = (_d = this.handlers).updateModelContext) == null ? void 0 : _e.call(_d, request.params)) != null ? _f : {};
|
|
899
|
+
case "ui/request-display-mode":
|
|
900
|
+
return (_j = (_h = (_g = this.handlers).requestDisplayMode) == null ? void 0 : _h.call(
|
|
901
|
+
_g,
|
|
902
|
+
request.params
|
|
903
|
+
)) != null ? _j : { mode: (_i = this.hostContext.displayMode) != null ? _i : "inline" };
|
|
904
|
+
default:
|
|
905
|
+
throw new Error(`Unsupported MCP App method: ${request.method}`);
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
/**
|
|
909
|
+
* Handles iframe lifecycle and telemetry notifications.
|
|
910
|
+
*/
|
|
911
|
+
handleNotification(notification) {
|
|
912
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
913
|
+
switch (notification.method) {
|
|
914
|
+
case "ui/notifications/initialized":
|
|
915
|
+
this.initialized = true;
|
|
916
|
+
this.flushNotifications();
|
|
917
|
+
(_b = (_a = this.handlers).onInitialized) == null ? void 0 : _b.call(_a);
|
|
918
|
+
break;
|
|
919
|
+
case "ui/notifications/size-changed":
|
|
920
|
+
(_d = (_c = this.handlers).onSizeChange) == null ? void 0 : _d.call(
|
|
921
|
+
_c,
|
|
922
|
+
notification.params
|
|
923
|
+
);
|
|
924
|
+
break;
|
|
925
|
+
case "ui/notifications/request-teardown":
|
|
926
|
+
(_f = (_e = this.handlers).onRequestTeardown) == null ? void 0 : _f.call(_e, notification.params);
|
|
927
|
+
break;
|
|
928
|
+
case "notifications/message":
|
|
929
|
+
(_h = (_g = this.handlers).onLog) == null ? void 0 : _h.call(_g, notification.params);
|
|
930
|
+
break;
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
/**
|
|
934
|
+
* Sends a host-to-iframe notification, queueing it until app initialization.
|
|
935
|
+
*/
|
|
936
|
+
sendNotification(notification) {
|
|
937
|
+
const message = { jsonrpc: "2.0", ...notification };
|
|
938
|
+
if (!this.initialized && !notification.method.includes("sandbox")) {
|
|
939
|
+
this.pendingNotifications.push(message);
|
|
940
|
+
return;
|
|
941
|
+
}
|
|
942
|
+
this.post(message);
|
|
943
|
+
}
|
|
944
|
+
/**
|
|
945
|
+
* Sends notifications that were queued before `ui/notifications/initialized`.
|
|
946
|
+
*/
|
|
947
|
+
flushNotifications() {
|
|
948
|
+
const notifications = this.pendingNotifications;
|
|
949
|
+
this.pendingNotifications = [];
|
|
950
|
+
for (const notification of notifications) {
|
|
951
|
+
this.post(notification);
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
/**
|
|
955
|
+
* Sends a host-initiated JSON-RPC request to the iframe.
|
|
956
|
+
*/
|
|
957
|
+
request(method, params) {
|
|
958
|
+
const id = this.nextRequestId++;
|
|
959
|
+
this.post({ jsonrpc: "2.0", id, method, params });
|
|
960
|
+
return new Promise((resolve2, reject) => {
|
|
961
|
+
this.pendingResponses.set(id, { resolve: resolve2, reject });
|
|
962
|
+
});
|
|
963
|
+
}
|
|
964
|
+
/**
|
|
965
|
+
* Posts a JSON-RPC message to the sandbox proxy iframe.
|
|
966
|
+
*/
|
|
967
|
+
post(message) {
|
|
968
|
+
this.targetWindow.postMessage(message, this.targetOrigin);
|
|
969
|
+
}
|
|
970
|
+
};
|
|
971
|
+
|
|
972
|
+
// src/mcp-apps/sandbox.ts
|
|
973
|
+
var MCP_APP_DEFAULT_OUTER_SANDBOX = "allow-scripts allow-same-origin allow-forms";
|
|
974
|
+
var MCP_APP_DEFAULT_INNER_SANDBOX = "allow-scripts allow-forms";
|
|
975
|
+
function getMCPAppCSP(csp) {
|
|
976
|
+
var _a, _b, _c;
|
|
977
|
+
if (csp == null) {
|
|
978
|
+
return void 0;
|
|
979
|
+
}
|
|
980
|
+
const connectSrc = ["'self'", ...(_a = csp.connectDomains) != null ? _a : []];
|
|
981
|
+
const imgSrc = ["'self'", "data:", ...(_b = csp.resourceDomains) != null ? _b : []];
|
|
982
|
+
const frameSrc = ["'self'", ...(_c = csp.frameDomains) != null ? _c : []];
|
|
983
|
+
return [
|
|
984
|
+
"default-src 'none'",
|
|
985
|
+
"script-src 'unsafe-inline'",
|
|
986
|
+
"style-src 'unsafe-inline'",
|
|
987
|
+
`connect-src ${connectSrc.join(" ")}`,
|
|
988
|
+
`img-src ${imgSrc.join(" ")}`,
|
|
989
|
+
`font-src ${imgSrc.join(" ")}`,
|
|
990
|
+
`frame-src ${frameSrc.join(" ")}`
|
|
991
|
+
].join("; ");
|
|
992
|
+
}
|
|
993
|
+
function getMCPAppAllowAttribute(permissions) {
|
|
994
|
+
if (permissions == null) {
|
|
995
|
+
return void 0;
|
|
996
|
+
}
|
|
997
|
+
const allow = [];
|
|
998
|
+
if (permissions.camera)
|
|
999
|
+
allow.push("camera");
|
|
1000
|
+
if (permissions.microphone)
|
|
1001
|
+
allow.push("microphone");
|
|
1002
|
+
if (permissions.geolocation)
|
|
1003
|
+
allow.push("geolocation");
|
|
1004
|
+
if (permissions.clipboardWrite)
|
|
1005
|
+
allow.push("clipboard-write");
|
|
1006
|
+
return allow.length > 0 ? allow.join("; ") : void 0;
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
// src/mcp-apps/utils.ts
|
|
1010
|
+
import { isJSONObject as isJSONObject2 } from "@ai-sdk/provider";
|
|
1011
|
+
function getMCPAppFromToolPart(part) {
|
|
1012
|
+
var _a;
|
|
1013
|
+
const mcpMetadata = (_a = part.toolMetadata) == null ? void 0 : _a.mcp;
|
|
1014
|
+
const rawAppMetadata = isJSONObject2(mcpMetadata) ? mcpMetadata.app : void 0;
|
|
1015
|
+
const appMetadata = isJSONObject2(rawAppMetadata) ? rawAppMetadata : void 0;
|
|
1016
|
+
if (appMetadata == null || appMetadata.mimeType !== "text/html;profile=mcp-app" || typeof appMetadata.resourceUri !== "string" || !appMetadata.resourceUri.startsWith("ui://") || appMetadata.visibility != null && (!Array.isArray(appMetadata.visibility) || appMetadata.visibility.some(
|
|
1017
|
+
(value) => value !== "model" && value !== "app"
|
|
1018
|
+
))) {
|
|
1019
|
+
return void 0;
|
|
1020
|
+
}
|
|
1021
|
+
return appMetadata;
|
|
1022
|
+
}
|
|
1023
|
+
function normalizeMCPAppToolResult(output) {
|
|
1024
|
+
if (output != null && typeof output === "object" && "content" in output) {
|
|
1025
|
+
return output;
|
|
1026
|
+
}
|
|
1027
|
+
return {
|
|
1028
|
+
content: [],
|
|
1029
|
+
structuredContent: output
|
|
1030
|
+
};
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
// src/mcp-apps/app-frame.tsx
|
|
1034
|
+
import { jsx } from "react/jsx-runtime";
|
|
1035
|
+
function sendToolState({
|
|
1036
|
+
bridge,
|
|
1037
|
+
input,
|
|
1038
|
+
output
|
|
1039
|
+
}) {
|
|
1040
|
+
if (bridge == null) {
|
|
1041
|
+
return;
|
|
1042
|
+
}
|
|
1043
|
+
if (input !== void 0) {
|
|
1044
|
+
bridge.sendToolInput(input);
|
|
1045
|
+
}
|
|
1046
|
+
if (output !== void 0) {
|
|
1047
|
+
bridge.sendToolResult(normalizeMCPAppToolResult(output));
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1050
|
+
function MCPAppFrame({
|
|
1051
|
+
app,
|
|
1052
|
+
resource,
|
|
1053
|
+
input,
|
|
1054
|
+
output,
|
|
1055
|
+
sandbox,
|
|
1056
|
+
handlers,
|
|
1057
|
+
hostInfo,
|
|
1058
|
+
hostContext
|
|
1059
|
+
}) {
|
|
1060
|
+
var _a, _b, _c, _d, _e, _f;
|
|
1061
|
+
const iframeRef = useRef5(null);
|
|
1062
|
+
const bridgeRef = useRef5(void 0);
|
|
1063
|
+
const inputRef = useRef5(input);
|
|
1064
|
+
const outputRef = useRef5(output);
|
|
1065
|
+
const hostContextRef = useRef5(hostContext);
|
|
1066
|
+
const initializedRef = useRef5(false);
|
|
1067
|
+
inputRef.current = input;
|
|
1068
|
+
outputRef.current = output;
|
|
1069
|
+
hostContextRef.current = hostContext;
|
|
1070
|
+
const targetOrigin = (_a = sandbox.targetOrigin) != null ? _a : "*";
|
|
1071
|
+
const sandboxUrl = String(sandbox.url);
|
|
1072
|
+
const resourceCSP = getMCPAppCSP((_b = resource.meta) == null ? void 0 : _b.csp);
|
|
1073
|
+
const resourceAllow = getMCPAppAllowAttribute((_c = resource.meta) == null ? void 0 : _c.permissions);
|
|
1074
|
+
const innerSandbox = (_d = sandbox.innerSandbox) != null ? _d : MCP_APP_DEFAULT_INNER_SANDBOX;
|
|
1075
|
+
const bridgeHandlers = useMemo(
|
|
1076
|
+
() => ({
|
|
1077
|
+
...handlers,
|
|
1078
|
+
onInitialized: () => {
|
|
1079
|
+
var _a2;
|
|
1080
|
+
initializedRef.current = true;
|
|
1081
|
+
(_a2 = handlers == null ? void 0 : handlers.onInitialized) == null ? void 0 : _a2.call(handlers);
|
|
1082
|
+
sendToolState({
|
|
1083
|
+
bridge: bridgeRef.current,
|
|
1084
|
+
input: inputRef.current,
|
|
1085
|
+
output: outputRef.current
|
|
1086
|
+
});
|
|
1087
|
+
}
|
|
1088
|
+
}),
|
|
1089
|
+
[handlers]
|
|
1090
|
+
);
|
|
1091
|
+
const bridgeHandlersRef = useRef5(bridgeHandlers);
|
|
1092
|
+
bridgeHandlersRef.current = bridgeHandlers;
|
|
1093
|
+
useEffect4(() => {
|
|
1094
|
+
const iframe = iframeRef.current;
|
|
1095
|
+
const targetWindow = iframe == null ? void 0 : iframe.contentWindow;
|
|
1096
|
+
if (targetWindow == null) {
|
|
1097
|
+
return;
|
|
1098
|
+
}
|
|
1099
|
+
initializedRef.current = false;
|
|
1100
|
+
const bridge = new MCPAppBridge({
|
|
1101
|
+
targetWindow,
|
|
1102
|
+
targetOrigin,
|
|
1103
|
+
handlers: bridgeHandlersRef.current,
|
|
1104
|
+
hostInfo,
|
|
1105
|
+
hostContext: hostContextRef.current
|
|
1106
|
+
});
|
|
1107
|
+
bridgeRef.current = bridge;
|
|
1108
|
+
const onMessage = (event) => {
|
|
1109
|
+
var _a2;
|
|
1110
|
+
if (event.source === targetWindow && ((_a2 = event.data) == null ? void 0 : _a2.jsonrpc) === "2.0" && event.data.method === "ui/notifications/sandbox-proxy-ready") {
|
|
1111
|
+
bridge.sendSandboxResourceReady({
|
|
1112
|
+
html: resource.html,
|
|
1113
|
+
csp: resourceCSP,
|
|
1114
|
+
sandbox: innerSandbox,
|
|
1115
|
+
allow: resourceAllow
|
|
1116
|
+
});
|
|
1117
|
+
return;
|
|
1118
|
+
}
|
|
1119
|
+
bridge.handleMessage(event);
|
|
1120
|
+
};
|
|
1121
|
+
window.addEventListener("message", onMessage);
|
|
1122
|
+
return () => {
|
|
1123
|
+
initializedRef.current = false;
|
|
1124
|
+
window.removeEventListener("message", onMessage);
|
|
1125
|
+
void bridge.teardownResource().catch(() => {
|
|
1126
|
+
});
|
|
1127
|
+
bridge.close();
|
|
1128
|
+
bridgeRef.current = void 0;
|
|
1129
|
+
};
|
|
1130
|
+
}, [
|
|
1131
|
+
hostInfo,
|
|
1132
|
+
innerSandbox,
|
|
1133
|
+
resource.html,
|
|
1134
|
+
resourceAllow,
|
|
1135
|
+
resourceCSP,
|
|
1136
|
+
sandboxUrl,
|
|
1137
|
+
targetOrigin
|
|
1138
|
+
]);
|
|
1139
|
+
useEffect4(() => {
|
|
1140
|
+
var _a2;
|
|
1141
|
+
(_a2 = bridgeRef.current) == null ? void 0 : _a2.setHandlers(bridgeHandlers);
|
|
1142
|
+
}, [bridgeHandlers]);
|
|
1143
|
+
useEffect4(() => {
|
|
1144
|
+
var _a2;
|
|
1145
|
+
if (hostContext != null) {
|
|
1146
|
+
(_a2 = bridgeRef.current) == null ? void 0 : _a2.setHostContext(hostContext);
|
|
1147
|
+
}
|
|
1148
|
+
}, [hostContext]);
|
|
1149
|
+
useEffect4(() => {
|
|
1150
|
+
var _a2;
|
|
1151
|
+
if (initializedRef.current && input !== void 0) {
|
|
1152
|
+
(_a2 = bridgeRef.current) == null ? void 0 : _a2.sendToolInput(input);
|
|
1153
|
+
}
|
|
1154
|
+
}, [input]);
|
|
1155
|
+
useEffect4(() => {
|
|
1156
|
+
var _a2;
|
|
1157
|
+
if (initializedRef.current && output !== void 0) {
|
|
1158
|
+
(_a2 = bridgeRef.current) == null ? void 0 : _a2.sendToolResult(normalizeMCPAppToolResult(output));
|
|
1159
|
+
}
|
|
1160
|
+
}, [output]);
|
|
1161
|
+
return /* @__PURE__ */ jsx(
|
|
1162
|
+
"iframe",
|
|
1163
|
+
{
|
|
1164
|
+
ref: iframeRef,
|
|
1165
|
+
title: "MCP App",
|
|
1166
|
+
"aria-label": (_e = sandbox.title) != null ? _e : app.resourceUri,
|
|
1167
|
+
src: sandboxUrl,
|
|
1168
|
+
className: sandbox.className,
|
|
1169
|
+
style: sandbox.style,
|
|
1170
|
+
sandbox: (_f = sandbox.outerSandbox) != null ? _f : MCP_APP_DEFAULT_OUTER_SANDBOX
|
|
1171
|
+
}
|
|
1172
|
+
);
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1175
|
+
// src/mcp-apps/app-renderer.tsx
|
|
1176
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
1177
|
+
function getToolPartOutput(part) {
|
|
1178
|
+
return part.state === "output-available" ? part.output : void 0;
|
|
1179
|
+
}
|
|
1180
|
+
function getToolPartInput(part) {
|
|
1181
|
+
return part.state === "input-available" || part.state === "output-available" ? part.input : void 0;
|
|
1182
|
+
}
|
|
1183
|
+
function MCPAppRenderer({
|
|
1184
|
+
part,
|
|
1185
|
+
sandbox,
|
|
1186
|
+
resource: resourceProp,
|
|
1187
|
+
loadResource,
|
|
1188
|
+
handlers,
|
|
1189
|
+
hostInfo,
|
|
1190
|
+
hostContext,
|
|
1191
|
+
fallback = null
|
|
1192
|
+
}) {
|
|
1193
|
+
const app = getMCPAppFromToolPart(part);
|
|
1194
|
+
const [cachedApp, setCachedApp] = useState3();
|
|
1195
|
+
const [loadedResource, setLoadedResource] = useState3();
|
|
1196
|
+
useEffect5(() => {
|
|
1197
|
+
if (app != null) {
|
|
1198
|
+
setCachedApp(
|
|
1199
|
+
(previous) => (previous == null ? void 0 : previous.resourceUri) === app.resourceUri ? previous : app
|
|
1200
|
+
);
|
|
1201
|
+
}
|
|
1202
|
+
}, [app == null ? void 0 : app.resourceUri]);
|
|
1203
|
+
const appForRender = app != null ? app : cachedApp;
|
|
1204
|
+
useEffect5(() => {
|
|
1205
|
+
if (appForRender == null || resourceProp != null || loadResource == null) {
|
|
1206
|
+
return;
|
|
1207
|
+
}
|
|
1208
|
+
let cancelled = false;
|
|
1209
|
+
const resourceUri = appForRender.resourceUri;
|
|
1210
|
+
loadResource(appForRender).then((resource2) => {
|
|
1211
|
+
if (!cancelled) {
|
|
1212
|
+
setLoadedResource({ resourceUri, resource: resource2 });
|
|
1213
|
+
}
|
|
1214
|
+
}).catch((error2) => {
|
|
1215
|
+
if (!cancelled) {
|
|
1216
|
+
setLoadedResource({
|
|
1217
|
+
resourceUri,
|
|
1218
|
+
error: error2 instanceof Error ? error2 : new Error(String(error2))
|
|
1219
|
+
});
|
|
1220
|
+
}
|
|
1221
|
+
});
|
|
1222
|
+
return () => {
|
|
1223
|
+
cancelled = true;
|
|
1224
|
+
};
|
|
1225
|
+
}, [appForRender == null ? void 0 : appForRender.resourceUri, loadResource, resourceProp]);
|
|
1226
|
+
const loadedResourceForApp = (loadedResource == null ? void 0 : loadedResource.resourceUri) === (appForRender == null ? void 0 : appForRender.resourceUri) ? loadedResource : void 0;
|
|
1227
|
+
const resource = resourceProp != null ? resourceProp : loadedResourceForApp == null ? void 0 : loadedResourceForApp.resource;
|
|
1228
|
+
const error = resourceProp == null ? loadedResourceForApp == null ? void 0 : loadedResourceForApp.error : void 0;
|
|
1229
|
+
if (appForRender == null || error != null || resource == null) {
|
|
1230
|
+
return fallback;
|
|
1231
|
+
}
|
|
1232
|
+
return /* @__PURE__ */ jsx2(
|
|
1233
|
+
MCPAppFrame,
|
|
1234
|
+
{
|
|
1235
|
+
app: appForRender,
|
|
1236
|
+
resource,
|
|
1237
|
+
input: getToolPartInput(part),
|
|
1238
|
+
output: getToolPartOutput(part),
|
|
1239
|
+
sandbox,
|
|
1240
|
+
handlers,
|
|
1241
|
+
hostInfo,
|
|
1242
|
+
hostContext
|
|
1243
|
+
}
|
|
1244
|
+
);
|
|
1245
|
+
}
|
|
1246
|
+
export {
|
|
533
1247
|
Chat,
|
|
1248
|
+
MCPAppRenderer as experimental_MCPAppRenderer,
|
|
534
1249
|
experimental_useObject,
|
|
1250
|
+
experimental_useRealtime,
|
|
535
1251
|
useChat,
|
|
536
1252
|
useCompletion
|
|
537
|
-
}
|
|
1253
|
+
};
|
|
538
1254
|
//# sourceMappingURL=index.js.map
|