@ai-sdk/react 4.0.0-beta.17 → 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/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
- var import_react = require("react");
21
+ import { useCallback, useEffect, useRef, useSyncExternalStore } from "react";
60
22
 
61
23
  // src/chat.react.ts
62
- var import_ai = require("ai");
24
+ import {
25
+ AbstractChat
26
+ } from "ai";
63
27
 
64
28
  // src/throttle.ts
65
- var import_throttleit = __toESM(require("throttleit"));
29
+ import throttleFunction from "throttleit";
66
30
  function throttle(fn, waitMs) {
67
- return waitMs != null ? (0, import_throttleit.default)(fn, waitMs) : fn;
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 import_ai.AbstractChat {
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 = (0, import_react.useRef)(
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 = (0, import_react.useRef)(
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 = (0, import_react.useCallback)(
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 = (0, import_react.useSyncExternalStore)(
197
+ const messages = useSyncExternalStore(
234
198
  subscribeToMessages,
235
199
  () => chatRef.current.messages,
236
200
  () => chatRef.current.messages
237
201
  );
238
- const status = (0, import_react.useSyncExternalStore)(
202
+ const status = useSyncExternalStore(
239
203
  chatRef.current["~registerStatusCallback"],
240
204
  () => chatRef.current.status,
241
205
  () => chatRef.current.status
242
206
  );
243
- const error = (0, import_react.useSyncExternalStore)(
207
+ const error = useSyncExternalStore(
244
208
  chatRef.current["~registerErrorCallback"],
245
209
  () => chatRef.current.error,
246
210
  () => chatRef.current.error
247
211
  );
248
- const setMessages = (0, import_react.useCallback)(
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
- (0, import_react.useEffect)(() => {
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
- var import_ai2 = require("ai");
284
- var import_react2 = require("react");
285
- var import_swr = __toESM(require("swr"));
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 = (0, import_react2.useId)();
266
+ const hookId = useId();
301
267
  const completionId = id || hookId;
302
- const { data, mutate } = (0, import_swr.default)([api, completionId], null, {
268
+ const { data, mutate } = useSWR([api, completionId], null, {
303
269
  fallbackData: initialCompletion
304
270
  });
305
- const { data: isLoading = false, mutate: mutateLoading } = (0, import_swr.default)(
271
+ const { data: isLoading = false, mutate: mutateLoading } = useSWR(
306
272
  [completionId, "loading"],
307
273
  null
308
274
  );
309
- const [error, setError] = (0, import_react2.useState)(void 0);
275
+ const [error, setError] = useState(void 0);
310
276
  const completion = data;
311
- const [abortController, setAbortController] = (0, import_react2.useState)(null);
312
- const extraMetadataRef = (0, import_react2.useRef)({
277
+ const [abortController, setAbortController] = useState(null);
278
+ const extraMetadataRef = useRef2({
313
279
  credentials,
314
280
  headers,
315
281
  body
316
282
  });
317
- (0, import_react2.useEffect)(() => {
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 = (0, import_react2.useCallback)(
325
- async (prompt, options) => (0, import_ai2.callCompletionApi)({
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 = (0, import_react2.useCallback)(() => {
327
+ const stop = useCallback2(() => {
362
328
  if (abortController) {
363
329
  abortController.abort();
364
330
  setAbortController(null);
365
331
  }
366
332
  }, [abortController]);
367
- const setCompletion = (0, import_react2.useCallback)(
333
+ const setCompletion = useCallback2(
368
334
  (completion2) => {
369
335
  mutate(completion2, false);
370
336
  },
371
337
  [mutate]
372
338
  );
373
- const complete = (0, import_react2.useCallback)(
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] = (0, import_react2.useState)(initialInput);
380
- const handleSubmit = (0, import_react2.useCallback)(
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 = (0, import_react2.useCallback)(
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
- var import_provider_utils = require("@ai-sdk/provider-utils");
410
- var import_ai3 = require("ai");
411
- var import_react3 = require("react");
412
- var import_swr2 = __toESM(require("swr"));
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 = (0, import_react3.useId)();
401
+ const hookId = useId2();
427
402
  const completionId = id != null ? id : hookId;
428
- const { data, mutate } = (0, import_swr2.default)(
403
+ const { data, mutate } = useSWR2(
429
404
  [api, completionId],
430
405
  null,
431
406
  { fallbackData: initialValue }
432
407
  );
433
- const [error, setError] = (0, import_react3.useState)(void 0);
434
- const [isLoading, setIsLoading] = (0, import_react3.useState)(false);
435
- const abortControllerRef = (0, import_react3.useRef)(null);
436
- const stop = (0, import_react3.useCallback)(() => {
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 (ignored) {
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 (0, import_provider_utils.resolve)(headers);
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
- ...(0, import_provider_utils.normalizeHeaders)(resolvedHeaders)
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 (0, import_ai3.parsePartialJson)(accumulatedText);
454
+ const { value } = await parsePartialJson(accumulatedText);
480
455
  const currentObject = value;
481
- if (!(0, import_ai3.isDeepEqualData)(latestObject, currentObject)) {
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 (0, import_provider_utils.safeValidateTypes)({
465
+ const validationResult = await safeValidateTypes({
491
466
  value: latestObject,
492
- schema: (0, import_ai3.asSchema)(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 ((0, import_provider_utils.isAbortError)(error2)) {
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
- // Annotate the CommonJS export names for ESM import in node:
532
- 0 && (module.exports = {
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