@ai-sdk/react 4.0.104 → 4.0.106

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 CHANGED
@@ -1,5 +1,50 @@
1
1
  # @ai-sdk/react
2
2
 
3
+ ## 4.0.106
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [91c2128]
8
+ - Updated dependencies [df91a09]
9
+ - Updated dependencies [25a0447]
10
+ - Updated dependencies [2cd80b3]
11
+ - Updated dependencies [d06bb2a]
12
+ - Updated dependencies [123d71f]
13
+ - Updated dependencies [2fa5e0e]
14
+ - @ai-sdk/provider-utils@5.0.42
15
+ - ai@7.0.103
16
+ - @ai-sdk/mcp@2.0.51
17
+ - @ai-sdk/provider@4.0.16
18
+
19
+ ## 4.0.105
20
+
21
+ ### Patch Changes
22
+
23
+ - 5c0054d: Add optional browser-direct WebRTC for experimental client-delegated Live conversations alongside the existing WebSocket path. Exchange SDP through an application endpoint with `api.session`, configure server-owned data-channel permissions, and preserve committed React session ownership. Capture follows the selected sender track, borrowed tracks remain caller-owned, and disconnect recovery and finalization stay bounded. Applications continue to handle client delegation and submit context; Live session updates and Responses delegation remain unsupported.
24
+
25
+ Serialize microphone sender changes and close the peer if detachment fails, without stopping borrowed tracks. Validate nonempty SDP setup answers with a bounded response body, and document the same-origin broker authentication contract.
26
+
27
+ - a050aed: Preserve missing-tool-handler diagnostics in `experimental_useRealtime` by leaving an omitted `onToolCall` undefined. Publish handler presence only at commit without reconnecting or exposing handlers from abandoned renders. A defined handler returning undefined continues to support manual tool output.
28
+ - a050aed: Publish realtime session ownership and callbacks only when React commits. Keep control identities stable across renders, route retained controls to the current committed session, and revoke them on unmount. Preserve connected sessions when concurrent renders are abandoned, support StrictMode effect replay and React 18 server rendering, and expose continuous session metadata alongside turn-based messages.
29
+ - a050aed: Add WebSocket relay support to `experimental_useRealtime`, with shared session state, capture controls, bounded playback, graceful close, and application-handled client delegation for Live.
30
+ - 4b306c2: Add the client-delegation-first realtime WebSocket runtime with session lifecycle, exact final duration, bounded event queues and command acknowledgement tracking, transcripts, context append, and reversible capture. Continuous sessions support PCM16 audio-chunk playback over an application relay with a recoverable live-edge buffer policy. Legacy turn-based WebSockets retain queued playback and frontend tool handling.
31
+
32
+ Remove the deferred managed Responses coordinator, autoContinueTools option, backend usage state, and Live tool-result aliases. Continuous text and delegation handling belong to the application; sendTextMessage and addToolOutput reject continuous sessions. Server-confirmed provider delegation and turn-based audio-delta on the continuous profile fail explicitly. maxPlaybackBufferSeconds is supported only for continuous PCM sessions.
33
+
34
+ Fence callbacks, startup publications, tool results, and teardown by connection attempt. Validate token setup before opening a client-secret socket, require explicit relay transport mode, and include WebSocket URL, protocol values, and runtime timeouts/buffer settings in React session configuration keys.
35
+
36
+ Retain immediate local capture for explicit legacy preconnect streams, including owned-track cleanup and capture continuity through asynchronous setup. Signal transport closing before draining accepted terminal events, share reentrant close settlement, and cancel stale readiness and deadlines. Enforce 128 KiB frame and combined buffered-send budgets only for Live continuous sessions, using actual encoded wire bytes; oversized manual operations remain recoverable while startup and automatic audio failures close the session. Legacy startup, text, tool output, and audio retain their pre-Live behavior without these byte caps. Live pending-audio overflow drains accepted terminal usage within the existing one-second drain window. Validate final provider-transformed WebSocket URL syntax without removing native authentication query parameters.
37
+
38
+ - Updated dependencies [5c0054d]
39
+ - Updated dependencies [39535af]
40
+ - Updated dependencies [8b92ba9]
41
+ - Updated dependencies [4b306c2]
42
+ - Updated dependencies [4b306c2]
43
+ - @ai-sdk/provider@4.0.15
44
+ - ai@7.0.102
45
+ - @ai-sdk/mcp@2.0.50
46
+ - @ai-sdk/provider-utils@5.0.41
47
+
3
48
  ## 4.0.104
4
49
 
5
50
  ### Patch Changes
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { FlexibleSchema, FetchFunction, Resolvable, InferSchema } from '@ai-sdk/provider-utils';
2
- import { DeepPartial, UIMessage, AbstractChat, ChatInit, CompletionRequestOptions, UseCompletionOptions, Experimental_RealtimeSessionOptions, Experimental_RealtimeStatus, Experimental_RealtimeServerEvent, Experimental_AbstractRealtimeSession, Experimental_RealtimeState, ToolUIPart, UITools, DynamicToolUIPart } from 'ai';
2
+ import { DeepPartial, UIMessage, AbstractChat, ChatInit, CompletionRequestOptions, UseCompletionOptions, Experimental_RealtimeSessionOptions, Experimental_RealtimeStatus, Experimental_RealtimeServerEvent, Experimental_RealtimeState, Experimental_AbstractRealtimeSession, ToolUIPart, UITools, DynamicToolUIPart } from 'ai';
3
3
  export { CreateUIMessage, Experimental_RealtimeStatus, UIMessage, UseCompletionOptions } from 'ai';
4
4
  import * as react_jsx_runtime from 'react/jsx-runtime';
5
5
  import * as react from 'react';
@@ -197,11 +197,9 @@ declare class RealtimeStore extends Experimental_AbstractRealtimeSession {
197
197
  get events(): Experimental_RealtimeServerEvent[];
198
198
  get isCapturing(): boolean;
199
199
  get isPlaying(): boolean;
200
+ get session(): Experimental_RealtimeState['session'];
200
201
  subscribe(key: RealtimeStateKey, onChange: () => void): () => void;
201
202
  protected setState<K extends RealtimeStateKey>(key: K, value: Experimental_RealtimeState[K]): void;
202
- protected pushMessage(message: UIMessage): void;
203
- protected updateMessages(updater: (messages: UIMessage[]) => UIMessage[]): void;
204
- protected pushEvent(event: Experimental_RealtimeServerEvent): void;
205
203
  }
206
204
  type UseRealtimeReturn = {
207
205
  status: Experimental_RealtimeStatus;
@@ -209,7 +207,11 @@ type UseRealtimeReturn = {
209
207
  events: Experimental_RealtimeServerEvent[];
210
208
  isCapturing: boolean;
211
209
  isPlaying: boolean;
212
- connect: () => Promise<void>;
210
+ session?: Experimental_RealtimeState['session'];
211
+ connect: RealtimeStore['connect'];
212
+ close: RealtimeStore['close'];
213
+ resumePlayback: () => Promise<void>;
214
+ resumeAudioCapture: () => Promise<void>;
213
215
  disconnect: () => void;
214
216
  addToolOutput: (callId: string, result: unknown) => void;
215
217
  sendEvent: RealtimeStore['sendEvent'];
package/dist/index.js CHANGED
@@ -584,22 +584,20 @@ function useCompletion({
584
584
  }
585
585
 
586
586
  // src/use-realtime.ts
587
+ import { secureJsonParse } from "@ai-sdk/provider-utils";
587
588
  import {
588
589
  Experimental_AbstractRealtimeSession as AbstractRealtimeSession
589
590
  } from "ai";
590
- import { useCallback as useCallback4, useEffect as useEffect3, useRef as useRef4, useSyncExternalStore as useSyncExternalStore2 } from "react";
591
- function getRealtimeStoreKey(options) {
592
- return {
593
- model: options.model,
594
- token: options.api.token,
595
- sessionConfig: options.sessionConfig,
596
- sampleRate: options.sampleRate,
597
- maxEvents: options.maxEvents
598
- };
599
- }
600
- function shouldCreateRealtimeStore(currentKey, nextOptions) {
601
- return currentKey.model !== nextOptions.model || currentKey.token !== nextOptions.api.token || currentKey.sessionConfig !== nextOptions.sessionConfig || currentKey.sampleRate !== nextOptions.sampleRate || currentKey.maxEvents !== nextOptions.maxEvents;
602
- }
591
+ import {
592
+ useCallback as useCallback4,
593
+ useEffect as useEffect3,
594
+ useInsertionEffect,
595
+ useLayoutEffect,
596
+ useMemo as useMemo2,
597
+ useRef as useRef4,
598
+ useSyncExternalStore as useSyncExternalStore2
599
+ } from "react";
600
+ var useIsomorphicLayoutEffect = typeof window === "undefined" ? useEffect3 : useLayoutEffect;
603
601
  var RealtimeStore = class extends AbstractRealtimeSession {
604
602
  constructor() {
605
603
  super(...arguments);
@@ -615,7 +613,8 @@ var RealtimeStore = class extends AbstractRealtimeSession {
615
613
  messages: /* @__PURE__ */ new Set(),
616
614
  events: /* @__PURE__ */ new Set(),
617
615
  isCapturing: /* @__PURE__ */ new Set(),
618
- isPlaying: /* @__PURE__ */ new Set()
616
+ isPlaying: /* @__PURE__ */ new Set(),
617
+ session: /* @__PURE__ */ new Set()
619
618
  };
620
619
  }
621
620
  get status() {
@@ -633,6 +632,9 @@ var RealtimeStore = class extends AbstractRealtimeSession {
633
632
  get isPlaying() {
634
633
  return this.state.isPlaying;
635
634
  }
635
+ get session() {
636
+ return this.state.session;
637
+ }
636
638
  subscribe(key, onChange) {
637
639
  this.callbacks[key].add(onChange);
638
640
  return () => {
@@ -643,66 +645,105 @@ var RealtimeStore = class extends AbstractRealtimeSession {
643
645
  this.state = { ...this.state, [key]: value };
644
646
  this.callbacks[key].forEach((callback) => callback());
645
647
  }
646
- pushMessage(message) {
647
- this.state = {
648
- ...this.state,
649
- messages: [...this.state.messages, message]
650
- };
651
- this.callbacks.messages.forEach((callback) => callback());
652
- }
653
- updateMessages(updater) {
654
- this.state = {
655
- ...this.state,
656
- messages: updater(this.state.messages)
657
- };
658
- this.callbacks.messages.forEach((callback) => callback());
659
- }
660
- pushEvent(event) {
661
- const nextEvents = [...this.state.events, event];
662
- this.state = {
663
- ...this.state,
664
- events: nextEvents.length > this.maxEvents ? nextEvents.slice(-this.maxEvents) : nextEvents
665
- };
666
- this.callbacks.events.forEach((callback) => callback());
667
- }
668
648
  };
669
649
  function useRealtime(options) {
670
- const callbacksRef = useRef4({
671
- onToolCall: options.onToolCall,
672
- onEvent: options.onEvent,
673
- onError: options.onError
650
+ var _a;
651
+ const ownerRef = useRef4(null);
652
+ const {
653
+ model,
654
+ api,
655
+ startupTimeoutMs,
656
+ closeTimeoutMs,
657
+ rtcDisconnectTimeoutMs,
658
+ sessionConfig,
659
+ sampleRate,
660
+ maxEvents,
661
+ maxPlaybackBufferSeconds,
662
+ onToolCall,
663
+ onEvent,
664
+ onError
665
+ } = options;
666
+ const { token, websocket, session: sessionEndpoint } = api;
667
+ const protocols = JSON.stringify((_a = api.protocols) != null ? _a : []);
668
+ const rt = useMemo2(() => {
669
+ const store = new RealtimeStore({
670
+ model,
671
+ api: token != null ? { token } : sessionEndpoint != null ? { session: sessionEndpoint } : {
672
+ websocket,
673
+ protocols: secureJsonParse(protocols)
674
+ },
675
+ startupTimeoutMs,
676
+ closeTimeoutMs,
677
+ rtcDisconnectTimeoutMs,
678
+ sessionConfig,
679
+ sampleRate,
680
+ maxEvents,
681
+ maxPlaybackBufferSeconds,
682
+ onEvent: (...args) => {
683
+ var _a2, _b, _c;
684
+ return ((_a2 = ownerRef.current) == null ? void 0 : _a2.store) === store ? (_c = (_b = ownerRef.current).onEvent) == null ? void 0 : _c.call(_b, ...args) : void 0;
685
+ },
686
+ onError: (...args) => {
687
+ var _a2, _b, _c;
688
+ return ((_a2 = ownerRef.current) == null ? void 0 : _a2.store) === store ? (_c = (_b = ownerRef.current).onError) == null ? void 0 : _c.call(_b, ...args) : void 0;
689
+ }
690
+ });
691
+ return store;
692
+ }, [
693
+ model,
694
+ token,
695
+ sessionEndpoint,
696
+ websocket,
697
+ protocols,
698
+ startupTimeoutMs,
699
+ closeTimeoutMs,
700
+ rtcDisconnectTimeoutMs,
701
+ sessionConfig,
702
+ sampleRate,
703
+ maxEvents,
704
+ maxPlaybackBufferSeconds
705
+ ]);
706
+ useInsertionEffect(() => {
707
+ ownerRef.current = { store: rt, onToolCall, onEvent, onError };
708
+ rt.onToolCall = onToolCall == null ? void 0 : (...args) => {
709
+ var _a2, _b, _c;
710
+ return ((_a2 = ownerRef.current) == null ? void 0 : _a2.store) === rt ? (_c = (_b = ownerRef.current).onToolCall) == null ? void 0 : _c.call(_b, ...args) : void 0;
711
+ };
712
+ return () => {
713
+ ownerRef.current = null;
714
+ };
674
715
  });
675
- callbacksRef.current = {
676
- onToolCall: options.onToolCall,
677
- onEvent: options.onEvent,
678
- onError: options.onError
679
- };
680
- const realtimeRef = useRef4(null);
681
- let realtimeEntry = realtimeRef.current;
682
- if (realtimeEntry == null || shouldCreateRealtimeStore(realtimeEntry.key, options)) {
683
- realtimeEntry = {
684
- store: new RealtimeStore({
685
- ...options,
686
- onToolCall: (...args) => {
687
- var _a, _b;
688
- return (_b = (_a = callbacksRef.current).onToolCall) == null ? void 0 : _b.call(_a, ...args);
689
- },
690
- onEvent: (...args) => {
691
- var _a, _b;
692
- return (_b = (_a = callbacksRef.current).onEvent) == null ? void 0 : _b.call(_a, ...args);
693
- },
694
- onError: (...args) => {
695
- var _a, _b;
696
- return (_b = (_a = callbacksRef.current).onError) == null ? void 0 : _b.call(_a, ...args);
697
- }
698
- }),
699
- key: getRealtimeStoreKey(options)
716
+ useIsomorphicLayoutEffect(() => {
717
+ return () => rt.dispose();
718
+ }, [rt]);
719
+ const actions = useMemo2(() => {
720
+ const current = () => {
721
+ if (ownerRef.current == null)
722
+ throw new Error("Realtime controls require a mounted hook");
723
+ return ownerRef.current.store;
700
724
  };
701
- realtimeRef.current = realtimeEntry;
702
- } else {
703
- realtimeEntry.key = getRealtimeStoreKey(options);
704
- }
705
- const rt = realtimeEntry.store;
725
+ return {
726
+ connect: async (options2) => {
727
+ const store = current();
728
+ return options2 == null ? store.connect() : store.connect(options2);
729
+ },
730
+ close: async (options2) => current().close(options2),
731
+ resumePlayback: async () => current().resumePlayback(),
732
+ resumeAudioCapture: async () => current().resumeAudioCapture(),
733
+ disconnect: () => current().disconnect(),
734
+ addToolOutput: (callId, result) => current().addToolOutput(callId, result),
735
+ sendEvent: (event) => current().sendEvent(event),
736
+ sendTextMessage: (text) => current().sendTextMessage(text),
737
+ sendAudio: (audio) => current().sendAudio(audio),
738
+ commitAudio: () => current().commitAudio(),
739
+ clearAudioBuffer: () => current().clearAudioBuffer(),
740
+ requestResponse: (options2) => current().requestResponse(options2),
741
+ cancelResponse: () => current().cancelResponse(),
742
+ startAudioCapture: (stream) => current().startAudioCapture(stream),
743
+ stopAudioCapture: () => current().stopAudioCapture(),
744
+ stopPlayback: () => current().stopPlayback()
745
+ };
746
+ }, []);
706
747
  const status = useSyncExternalStore2(
707
748
  useCallback4((cb) => rt.subscribe("status", cb), [rt]),
708
749
  () => rt.status,
@@ -728,28 +769,19 @@ function useRealtime(options) {
728
769
  () => rt.isPlaying,
729
770
  () => rt.isPlaying
730
771
  );
731
- useEffect3(() => {
732
- return () => rt.dispose();
733
- }, [rt]);
772
+ const session = useSyncExternalStore2(
773
+ useCallback4((cb) => rt.subscribe("session", cb), [rt]),
774
+ () => rt.session,
775
+ () => rt.session
776
+ );
734
777
  return {
735
778
  status,
736
779
  messages,
737
780
  events,
738
781
  isCapturing,
739
782
  isPlaying,
740
- connect: rt.connect.bind(rt),
741
- disconnect: rt.disconnect.bind(rt),
742
- addToolOutput: rt.addToolOutput.bind(rt),
743
- sendEvent: rt.sendEvent.bind(rt),
744
- sendTextMessage: rt.sendTextMessage.bind(rt),
745
- sendAudio: rt.sendAudio.bind(rt),
746
- commitAudio: rt.commitAudio.bind(rt),
747
- clearAudioBuffer: rt.clearAudioBuffer.bind(rt),
748
- requestResponse: rt.requestResponse.bind(rt),
749
- cancelResponse: rt.cancelResponse.bind(rt),
750
- startAudioCapture: rt.startAudioCapture.bind(rt),
751
- stopAudioCapture: rt.stopAudioCapture.bind(rt),
752
- stopPlayback: rt.stopPlayback.bind(rt)
783
+ session,
784
+ ...actions
753
785
  };
754
786
  }
755
787
  var experimental_useRealtime = useRealtime;
@@ -758,7 +790,7 @@ var experimental_useRealtime = useRealtime;
758
790
  import { useEffect as useEffect5, useState as useState3 } from "react";
759
791
 
760
792
  // src/mcp-apps/app-frame.tsx
761
- import { useEffect as useEffect4, useMemo as useMemo2, useRef as useRef5 } from "react";
793
+ import { useEffect as useEffect4, useMemo as useMemo3, useRef as useRef5 } from "react";
762
794
 
763
795
  // src/mcp-apps/bridge.ts
764
796
  import { isJSONObject } from "@ai-sdk/provider";
@@ -1231,7 +1263,7 @@ function MCPAppFrame({
1231
1263
  sandbox.allowedPermissions
1232
1264
  );
1233
1265
  const innerSandbox = (_d = sandbox.innerSandbox) != null ? _d : MCP_APP_DEFAULT_INNER_SANDBOX;
1234
- const bridgeHandlers = useMemo2(
1266
+ const bridgeHandlers = useMemo3(
1235
1267
  () => ({
1236
1268
  ...handlers,
1237
1269
  onInitialized: () => {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/use-object.ts","../src/use-chat.ts","../src/chat.react.ts","../src/throttle.ts","../src/use-completion.ts","../src/use-realtime.ts","../src/mcp-apps/app-renderer.tsx","../src/mcp-apps/app-frame.tsx","../src/mcp-apps/bridge.ts","../src/mcp-apps/sandbox.ts","../src/mcp-apps/utils.ts","../src/index.ts"],"sourcesContent":["import {\n isAbortError,\n resolve,\n normalizeHeaders,\n safeValidateTypes,\n type FetchFunction,\n type FlexibleSchema,\n type InferSchema,\n type Resolvable,\n} from '@ai-sdk/provider-utils';\nimport {\n asSchema,\n isDeepEqualData,\n parsePartialJson,\n type DeepPartial,\n} from 'ai';\nimport { useCallback, useId, useRef, useState } from 'react';\nimport useSWR from 'swr';\n\n// use function to allow for mocking in tests:\nconst getOriginalFetch = () => fetch;\n\nexport type UseObjectOptions<SCHEMA extends FlexibleSchema, RESULT> = {\n /**\n * The API endpoint. It should stream JSON that matches the schema as chunked text.\n */\n api: string;\n\n /**\n * A schema that defines the shape of the complete object.\n */\n schema: SCHEMA;\n\n /**\n * An unique identifier. If not provided, a random one will be\n * generated. When provided, the `useObject` hook with the same `id` will\n * have shared states across components.\n */\n id?: string;\n\n /**\n * An optional value for the initial object.\n */\n initialValue?: DeepPartial<RESULT>;\n\n /**\n * Custom fetch implementation. You can use it as a middleware to intercept requests,\n * or to provide a custom fetch implementation for e.g. testing.\n */\n fetch?: FetchFunction;\n\n /**\n * Callback that is called when the stream has finished.\n */\n onFinish?: (event: {\n /**\n * The generated object (typed according to the schema).\n * Can be undefined if the final object does not match the schema.\n */\n object: RESULT | undefined;\n\n /**\n * Optional error object. This is e.g. a TypeValidationError when the final object does not match the schema.\n */\n error: Error | undefined;\n }) => Promise<void> | void;\n\n /**\n * Callback function to be called when an error is encountered.\n */\n onError?: (error: Error) => void;\n\n /**\n * Additional HTTP headers to be included in the request.\n * Can be a static object, a function that returns headers, or an async function\n * for dynamic auth tokens.\n */\n headers?: Resolvable<Record<string, string> | Headers>;\n\n /**\n * The credentials mode to be used for the fetch request.\n * Possible values are: 'omit', 'same-origin', 'include'.\n * Defaults to 'same-origin'.\n */\n credentials?: RequestCredentials;\n};\n\nexport type UseObjectHelpers<RESULT, INPUT> = {\n /**\n * Calls the API with the provided input as JSON body.\n */\n submit: (input: INPUT) => void;\n\n /**\n * The current value for the generated object. Updated as the API streams JSON chunks.\n */\n object: DeepPartial<RESULT> | undefined;\n\n /**\n * The error object of the API request if any.\n */\n error: Error | undefined;\n\n /**\n * Flag that indicates whether an API request is in progress.\n */\n isLoading: boolean;\n\n /**\n * Abort the current request immediately, keep the current partial object if any.\n */\n stop: () => void;\n\n /**\n * Clear the object state.\n */\n clear: () => void;\n};\n\nexport function useObject<\n SCHEMA extends FlexibleSchema,\n RESULT = InferSchema<SCHEMA>,\n INPUT = any,\n>({\n api,\n id,\n schema, // required, in the future we will use it for validation\n initialValue,\n fetch,\n onError,\n onFinish,\n headers,\n credentials,\n}: UseObjectOptions<SCHEMA, RESULT>): UseObjectHelpers<RESULT, INPUT> {\n // Generate an unique id if not provided.\n const hookId = useId();\n const completionId = id ?? hookId;\n\n // Store the completion state in SWR, using the completionId as the key to share states.\n const { data, mutate } = useSWR<DeepPartial<RESULT>>(\n [completionId, 'object'],\n null,\n { fallbackData: initialValue },\n );\n\n const [error, setError] = useState<undefined | Error>(undefined);\n const [isLoading, setIsLoading] = useState(false);\n\n // Abort controller to cancel the current API call.\n const abortControllerRef = useRef<AbortController | null>(null);\n\n const stop = useCallback(() => {\n try {\n abortControllerRef.current?.abort();\n } catch {\n } finally {\n setIsLoading(false);\n abortControllerRef.current = null;\n }\n }, []);\n\n const submit = async (input: INPUT) => {\n try {\n clearObject();\n\n setIsLoading(true);\n\n const abortController = new AbortController();\n abortControllerRef.current = abortController;\n\n // Resolve headers at request time (supports async functions for dynamic auth tokens)\n const resolvedHeaders = await resolve(headers);\n\n const actualFetch = fetch ?? getOriginalFetch();\n const response = await actualFetch(api, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...normalizeHeaders(resolvedHeaders),\n },\n credentials,\n signal: abortController.signal,\n body: JSON.stringify(input),\n });\n\n if (!response.ok) {\n throw new Error(\n (await response.text()) || 'Failed to fetch the response.',\n );\n }\n\n if (response.body == null) {\n throw new Error('The response body is empty.');\n }\n\n let accumulatedText = '';\n let latestObject: DeepPartial<RESULT> | undefined = undefined;\n\n await response.body.pipeThrough(new TextDecoderStream()).pipeTo(\n new WritableStream<string>({\n async write(chunk) {\n accumulatedText += chunk;\n\n const { value } = await parsePartialJson(accumulatedText);\n const currentObject = value as DeepPartial<RESULT>;\n\n if (!isDeepEqualData(latestObject, currentObject)) {\n latestObject = currentObject;\n\n mutate(currentObject);\n }\n },\n\n async close() {\n setIsLoading(false);\n abortControllerRef.current = null;\n\n if (onFinish != null) {\n const validationResult = await safeValidateTypes({\n value: latestObject,\n schema: asSchema(schema),\n });\n\n onFinish(\n validationResult.success\n ? { object: validationResult.value, error: undefined }\n : { object: undefined, error: validationResult.error },\n );\n }\n },\n }),\n );\n } catch (error) {\n if (isAbortError(error)) {\n return;\n }\n\n if (onError && error instanceof Error) {\n onError(error);\n }\n\n setIsLoading(false);\n setError(error instanceof Error ? error : new Error(String(error)));\n }\n };\n\n const clear = () => {\n stop();\n clearObject();\n };\n\n const clearObject = () => {\n setError(undefined);\n setIsLoading(false);\n mutate(undefined);\n };\n\n return {\n submit,\n object: data,\n error,\n isLoading,\n stop,\n clear,\n };\n}\n","import {\n type AbstractChat,\n type ChatInit,\n type ChatTransport,\n type CreateUIMessage,\n type UIMessage,\n DefaultChatTransport,\n} from 'ai';\nimport {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useSyncExternalStore,\n} from 'react';\nimport { Chat } from './chat.react';\n\nexport type { CreateUIMessage, UIMessage };\n\nexport type UseChatHelpers<UI_MESSAGE extends UIMessage> = {\n /**\n * The id of the chat.\n */\n readonly id: string;\n\n /**\n * Update the `messages` state locally. This is useful when you want to\n * edit the messages on the client, and then trigger the `reload` method\n * manually to regenerate the AI response.\n */\n setMessages: (\n messages: UI_MESSAGE[] | ((messages: UI_MESSAGE[]) => UI_MESSAGE[]),\n ) => void;\n\n error: Error | undefined;\n} & Pick<\n AbstractChat<UI_MESSAGE>,\n | 'sendMessage'\n | 'regenerate'\n | 'stop'\n | 'resumeStream'\n | 'addToolResult'\n | 'addToolOutput'\n | 'addToolApprovalResponse'\n | 'status'\n | 'messages'\n | 'clearError'\n>;\n\nexport type UseChatOptions<UI_MESSAGE extends UIMessage> = (\n | { chat: Chat<UI_MESSAGE> }\n | ChatInit<UI_MESSAGE>\n) & {\n /**\n * Custom throttle wait in ms for the chat messages and data updates.\n * Default is undefined, which disables throttling.\n */\n throttle?: number;\n\n /**\n * @deprecated Use `throttle` instead.\n */\n experimental_throttle?: number;\n\n /**\n * Whether to resume an ongoing chat generation stream.\n */\n resume?: boolean;\n};\n\nexport function useChat<UI_MESSAGE extends UIMessage = UIMessage>({\n throttle,\n experimental_throttle,\n resume = false,\n ...options\n}: UseChatOptions<UI_MESSAGE> = {}): UseChatHelpers<UI_MESSAGE> {\n const throttleWaitMs = throttle ?? experimental_throttle;\n // the Chat instance is created once and not recreated when options change,\n // so it would normally keep the callbacks/transport from the first render forever\n\n // keep latest values in a ref that is refreshed on every render,\n // and hand `Chat` stable wrappers that read from it to avoid stale closures\n const latestRef = useRef<\n Partial<\n Pick<\n ChatInit<UI_MESSAGE>,\n | 'onToolCall'\n | 'onData'\n | 'onFinish'\n | 'onError'\n | 'sendAutomaticallyWhen'\n | 'transport'\n >\n >\n >({});\n\n if (!('chat' in options)) {\n latestRef.current = {\n onToolCall: options.onToolCall,\n onData: options.onData,\n onFinish: options.onFinish,\n onError: options.onError,\n sendAutomaticallyWhen: options.sendAutomaticallyWhen,\n transport: options.transport,\n };\n }\n\n // resolve the latest transport and fallback to a lazily created default transport\n let defaultTransport: ChatTransport<UI_MESSAGE> | undefined;\n const getTransport = () =>\n latestRef.current.transport ??\n (defaultTransport ??= new DefaultChatTransport<UI_MESSAGE>());\n\n // give `Chat` stable wrappers that always read the latest values from `latestRef`\n const chatOptions: typeof options = {\n ...options,\n transport: {\n sendMessages: sendOptions => getTransport().sendMessages(sendOptions),\n reconnectToStream: reconnectOptions =>\n getTransport().reconnectToStream(reconnectOptions),\n },\n onToolCall: arg => latestRef.current.onToolCall?.(arg),\n onData: arg => latestRef.current.onData?.(arg),\n onFinish: arg => latestRef.current.onFinish?.(arg),\n onError: arg => latestRef.current.onError?.(arg),\n sendAutomaticallyWhen: arg =>\n latestRef.current.sendAutomaticallyWhen?.(arg) ?? false,\n };\n\n const chatKey = 'chat' in options ? options.chat : options.id;\n const { chat, isExternallyManaged } = useMemo(\n () => ({\n chat: 'chat' in options ? options.chat : new Chat(chatOptions),\n isExternallyManaged: 'chat' in options,\n }),\n [chatKey],\n );\n\n useEffect(() => {\n if (isExternallyManaged) {\n return;\n }\n\n return () => {\n void chat.stop();\n };\n }, [chat, isExternallyManaged]);\n\n const messagesSnapshot = useMemo(() => ({ messages: chat.messages }), [chat]);\n\n const subscribeToMessages = useCallback(\n (update: () => void) => {\n let isSubscribed = true;\n\n const updateMessages = () => {\n if (!isSubscribed) {\n return;\n }\n\n messagesSnapshot.messages = chat.messages;\n update();\n };\n\n const unsubscribe = chat['~registerMessagesCallback'](\n updateMessages,\n throttleWaitMs,\n );\n\n // Synchronize changes that may have happened between render and\n // subscription. useSyncExternalStore checks the snapshot after\n // subscribing and schedules a render when it changed.\n messagesSnapshot.messages = chat.messages;\n\n return () => {\n isSubscribed = false;\n unsubscribe();\n };\n },\n [chat, messagesSnapshot, throttleWaitMs],\n );\n\n const getMessagesSnapshot = useCallback(\n () => messagesSnapshot.messages,\n [messagesSnapshot],\n );\n\n const messages = useSyncExternalStore(\n subscribeToMessages,\n getMessagesSnapshot,\n getMessagesSnapshot,\n );\n\n const subscribeToStatus = useCallback(\n (update: () => void) =>\n chat['~registerStatusCallback'](() => {\n if (chat.status === 'ready' || chat.status === 'error') {\n // Publish the latest messages before the terminal status can render.\n messagesSnapshot.messages = chat.messages;\n }\n\n update();\n }),\n [chat, messagesSnapshot],\n );\n\n const getStatusSnapshot = useCallback(() => chat.status, [chat]);\n\n const status = useSyncExternalStore(\n subscribeToStatus,\n getStatusSnapshot,\n getStatusSnapshot,\n );\n\n const error = useSyncExternalStore(\n chat['~registerErrorCallback'],\n () => chat.error,\n () => chat.error,\n );\n\n const setMessages = useCallback(\n (\n messagesParam: UI_MESSAGE[] | ((messages: UI_MESSAGE[]) => UI_MESSAGE[]),\n ) => {\n if (typeof messagesParam === 'function') {\n messagesParam = messagesParam(chat.messages);\n }\n chat.messages = messagesParam;\n },\n [chat],\n );\n\n useEffect(() => {\n if (resume) {\n chat.resumeStream();\n }\n }, [resume, chat]);\n\n return {\n id: chat.id,\n messages,\n setMessages,\n sendMessage: chat.sendMessage,\n regenerate: chat.regenerate,\n clearError: chat.clearError,\n stop: chat.stop,\n error,\n resumeStream: chat.resumeStream,\n status,\n /**\n * @deprecated Use `addToolOutput` instead.\n */\n addToolResult: chat.addToolOutput,\n addToolOutput: chat.addToolOutput,\n addToolApprovalResponse: chat.addToolApprovalResponse,\n };\n}\n","import {\n AbstractChat,\n type ChatInit,\n type ChatState,\n type ChatStatus,\n type UIMessage,\n} from 'ai';\nimport { throttle } from './throttle';\n\nfunction cloneMetadata<METADATA>(metadata: METADATA): METADATA {\n if (Array.isArray(metadata)) {\n return [...metadata] as METADATA;\n }\n\n if (\n metadata != null &&\n typeof metadata === 'object' &&\n (Object.getPrototypeOf(metadata) === Object.prototype ||\n Object.getPrototypeOf(metadata) === null)\n ) {\n return { ...metadata } as METADATA;\n }\n\n return metadata;\n}\n\nclass ReactChatState<\n UI_MESSAGE extends UIMessage,\n> implements ChatState<UI_MESSAGE> {\n #messages: UI_MESSAGE[];\n #status: ChatStatus = 'ready';\n #error: Error | undefined = undefined;\n\n #messagesCallbacks = new Set<() => void>();\n #statusCallbacks = new Set<() => void>();\n #errorCallbacks = new Set<() => void>();\n\n constructor(initialMessages: UI_MESSAGE[] = []) {\n this.#messages = initialMessages;\n }\n\n get status(): ChatStatus {\n return this.#status;\n }\n\n set status(newStatus: ChatStatus) {\n this.#status = newStatus;\n this.#callStatusCallbacks();\n }\n\n get error(): Error | undefined {\n return this.#error;\n }\n\n set error(newError: Error | undefined) {\n this.#error = newError;\n this.#callErrorCallbacks();\n }\n\n get messages(): UI_MESSAGE[] {\n return this.#messages;\n }\n\n set messages(newMessages: UI_MESSAGE[]) {\n this.#messages = [...newMessages];\n this.#callMessagesCallbacks();\n }\n\n pushMessage = (message: UI_MESSAGE) => {\n this.#messages = this.#messages.concat(message);\n this.#callMessagesCallbacks();\n };\n\n popMessage = () => {\n this.#messages = this.#messages.slice(0, -1);\n this.#callMessagesCallbacks();\n };\n\n replaceMessage = (index: number, message: UI_MESSAGE) => {\n this.#messages = [\n ...this.#messages.slice(0, index),\n this.snapshot(message),\n ...this.#messages.slice(index + 1),\n ];\n this.#callMessagesCallbacks();\n };\n\n snapshot = <T>(value: T): T => {\n if (\n value == null ||\n typeof value !== 'object' ||\n !('parts' in value) ||\n !Array.isArray(value.parts)\n ) {\n return value;\n }\n\n const message = value as UI_MESSAGE;\n const snapshot = {\n ...message,\n parts: message.parts.map(part => ({ ...part })),\n };\n\n if ('metadata' in message) {\n snapshot.metadata = cloneMetadata(message.metadata);\n }\n\n return snapshot as T;\n };\n\n '~registerMessagesCallback' = (\n onChange: () => void,\n throttleWaitMs?: number,\n ): (() => void) => {\n const callback = throttleWaitMs\n ? throttle(onChange, throttleWaitMs)\n : onChange;\n this.#messagesCallbacks.add(callback);\n return () => {\n this.#messagesCallbacks.delete(callback);\n };\n };\n\n '~registerStatusCallback' = (onChange: () => void): (() => void) => {\n this.#statusCallbacks.add(onChange);\n return () => {\n this.#statusCallbacks.delete(onChange);\n };\n };\n\n '~registerErrorCallback' = (onChange: () => void): (() => void) => {\n this.#errorCallbacks.add(onChange);\n return () => {\n this.#errorCallbacks.delete(onChange);\n };\n };\n\n #callMessagesCallbacks = () => {\n this.#messagesCallbacks.forEach(callback => callback());\n };\n\n #callStatusCallbacks = () => {\n this.#statusCallbacks.forEach(callback => callback());\n };\n\n #callErrorCallbacks = () => {\n this.#errorCallbacks.forEach(callback => callback());\n };\n}\n\nexport class Chat<\n UI_MESSAGE extends UIMessage,\n> extends AbstractChat<UI_MESSAGE> {\n #state: ReactChatState<UI_MESSAGE>;\n\n constructor({ messages, ...init }: ChatInit<UI_MESSAGE>) {\n const state = new ReactChatState(messages);\n super({ ...init, state });\n this.#state = state;\n }\n\n '~registerMessagesCallback' = (\n onChange: () => void,\n throttleWaitMs?: number,\n ): (() => void) =>\n this.#state['~registerMessagesCallback'](onChange, throttleWaitMs);\n\n '~registerStatusCallback' = (onChange: () => void): (() => void) =>\n this.#state['~registerStatusCallback'](onChange);\n\n '~registerErrorCallback' = (onChange: () => void): (() => void) =>\n this.#state['~registerErrorCallback'](onChange);\n}\n","import throttleFunction from 'throttleit';\n\nexport function throttle<T extends (...args: any[]) => any>(\n fn: T,\n waitMs: number | undefined,\n): T {\n return waitMs != null ? throttleFunction(fn, waitMs) : fn;\n}\n","import {\n callCompletionApi,\n type CompletionRequestOptions,\n type UseCompletionOptions,\n} from 'ai';\nimport { useCallback, useEffect, useId, useRef, useState } from 'react';\nimport useSWR from 'swr';\nimport { throttle } from './throttle';\n\nexport type { UseCompletionOptions };\n\nexport type UseCompletionHelpers<BODY extends object = object> = {\n /** The current completion result */\n completion: string;\n /**\n * Send a new prompt to the API endpoint and update the completion state.\n */\n complete: (\n prompt: string,\n options?: CompletionRequestOptions<BODY>,\n ) => Promise<string | null | undefined>;\n /** The error object of the API request */\n error: undefined | Error;\n /**\n * Abort the current API request but keep the generated tokens.\n */\n stop: () => void;\n /**\n * Update the `completion` state locally.\n */\n setCompletion: (completion: string) => void;\n /** The current value of the input */\n input: string;\n /** setState-powered method to update the input value */\n setInput: React.Dispatch<React.SetStateAction<string>>;\n /**\n * An input/textarea-ready onChange handler to control the value of the input\n * @example\n * ```jsx\n * <input onChange={handleInputChange} value={input} />\n * ```\n */\n handleInputChange: (\n event:\n | React.ChangeEvent<HTMLInputElement>\n | React.ChangeEvent<HTMLTextAreaElement>,\n ) => void;\n\n /**\n * Form submission handler to automatically reset input and append a user message\n * @example\n * ```jsx\n * <form onSubmit={handleSubmit}>\n * <input onChange={handleInputChange} value={input} />\n * </form>\n * ```\n */\n handleSubmit: (event?: { preventDefault?: () => void }) => void;\n\n /** Whether the API request is in progress */\n isLoading: boolean;\n};\n\nexport function useCompletion<BODY extends object = object>({\n api = '/api/completion',\n id,\n initialCompletion = '',\n initialInput = '',\n credentials,\n headers,\n body,\n streamProtocol = 'data',\n fetch,\n onFinish,\n onError,\n throttle: throttleWait,\n experimental_throttle,\n}: UseCompletionOptions<NoInfer<BODY>> & {\n /**\n * Custom throttle wait in ms for the completion and data updates.\n * Default is undefined, which disables throttling.\n */\n throttle?: number;\n\n /**\n * @deprecated Use `throttle` instead.\n */\n experimental_throttle?: number;\n} = {}): UseCompletionHelpers<BODY> {\n const throttleWaitMs = throttleWait ?? experimental_throttle;\n // Generate an unique id for the completion if not provided.\n const hookId = useId();\n const completionId = id || hookId;\n\n // Store the completion state in SWR, using the completionId as the key to share states.\n const { data, mutate } = useSWR<string>([api, completionId], null, {\n fallbackData: initialCompletion,\n });\n\n const { data: isLoading = false, mutate: mutateLoading } = useSWR<boolean>(\n [completionId, 'loading'],\n null,\n );\n\n const [error, setError] = useState<undefined | Error>(undefined);\n const completion = data!;\n\n // Abort controller to cancel the current API call.\n const [abortController, setAbortController] =\n useState<AbortController | null>(null);\n\n const extraMetadataRef = useRef({\n credentials,\n headers,\n body,\n });\n\n useEffect(() => {\n extraMetadataRef.current = {\n credentials,\n headers,\n body,\n };\n }, [credentials, headers, body]);\n\n const triggerRequest = useCallback(\n async (prompt: string, options?: CompletionRequestOptions<BODY>) =>\n callCompletionApi({\n api,\n prompt,\n credentials: extraMetadataRef.current.credentials,\n headers: { ...extraMetadataRef.current.headers, ...options?.headers },\n body: {\n ...extraMetadataRef.current.body,\n ...options?.body,\n },\n streamProtocol,\n fetch,\n // throttle streamed ui updates:\n setCompletion: throttle(\n (completion: string) => mutate(completion, false),\n throttleWaitMs,\n ),\n setLoading: mutateLoading,\n setError,\n setAbortController,\n onFinish,\n onError,\n }),\n [\n mutate,\n mutateLoading,\n api,\n extraMetadataRef,\n setAbortController,\n onFinish,\n onError,\n setError,\n streamProtocol,\n fetch,\n throttleWaitMs,\n ],\n );\n\n const stop = useCallback(() => {\n if (abortController) {\n abortController.abort();\n setAbortController(null);\n }\n }, [abortController]);\n\n const setCompletion = useCallback(\n (completion: string) => {\n mutate(completion, false);\n },\n [mutate],\n );\n\n const complete = useCallback<UseCompletionHelpers<BODY>['complete']>(\n async (prompt, options) => {\n return triggerRequest(prompt, options);\n },\n [triggerRequest],\n );\n\n const [input, setInput] = useState(initialInput);\n\n const handleSubmit = useCallback(\n (event?: { preventDefault?: () => void }) => {\n event?.preventDefault?.();\n if (!input) {\n return;\n }\n\n const result = complete(input);\n setInput('');\n return result;\n },\n [input, complete, setInput],\n );\n\n const handleInputChange = useCallback(\n (e: any) => {\n setInput(e.target.value);\n },\n [setInput],\n );\n\n return {\n completion,\n complete,\n error,\n setCompletion,\n stop,\n input,\n setInput,\n handleInputChange,\n handleSubmit,\n isLoading,\n };\n}\n","import {\n Experimental_AbstractRealtimeSession as AbstractRealtimeSession,\n type Experimental_RealtimeServerEvent as RealtimeServerEvent,\n type Experimental_RealtimeSessionOptions as RealtimeSessionOptions,\n type Experimental_RealtimeState as RealtimeState,\n type Experimental_RealtimeStatus as RealtimeStatus,\n type UIMessage,\n} from 'ai';\nimport { useCallback, useEffect, useRef, useSyncExternalStore } from 'react';\n\ntype UseRealtimeOptions = RealtimeSessionOptions;\n\ntype RealtimeStateKey = keyof RealtimeState;\ntype RealtimeStoreKey = {\n model: RealtimeSessionOptions['model'];\n token: RealtimeSessionOptions['api']['token'];\n sessionConfig: RealtimeSessionOptions['sessionConfig'];\n sampleRate: RealtimeSessionOptions['sampleRate'];\n maxEvents: RealtimeSessionOptions['maxEvents'];\n};\n\nfunction getRealtimeStoreKey(options: UseRealtimeOptions): RealtimeStoreKey {\n return {\n model: options.model,\n token: options.api.token,\n sessionConfig: options.sessionConfig,\n sampleRate: options.sampleRate,\n maxEvents: options.maxEvents,\n };\n}\n\nfunction shouldCreateRealtimeStore(\n currentKey: RealtimeStoreKey,\n nextOptions: UseRealtimeOptions,\n): boolean {\n return (\n currentKey.model !== nextOptions.model ||\n currentKey.token !== nextOptions.api.token ||\n currentKey.sessionConfig !== nextOptions.sessionConfig ||\n currentKey.sampleRate !== nextOptions.sampleRate ||\n currentKey.maxEvents !== nextOptions.maxEvents\n );\n}\n\nclass RealtimeStore extends AbstractRealtimeSession {\n protected state: RealtimeState = {\n status: 'disconnected',\n messages: [],\n events: [],\n isCapturing: false,\n isPlaying: false,\n };\n\n private callbacks: { [K in RealtimeStateKey]: Set<() => void> } = {\n status: new Set(),\n messages: new Set(),\n events: new Set(),\n isCapturing: new Set(),\n isPlaying: new Set(),\n };\n\n get status(): RealtimeStatus {\n return this.state.status;\n }\n\n get messages(): UIMessage[] {\n return this.state.messages;\n }\n\n get events(): RealtimeServerEvent[] {\n return this.state.events;\n }\n\n get isCapturing(): boolean {\n return this.state.isCapturing;\n }\n\n get isPlaying(): boolean {\n return this.state.isPlaying;\n }\n\n subscribe(key: RealtimeStateKey, onChange: () => void): () => void {\n this.callbacks[key].add(onChange);\n\n return () => {\n this.callbacks[key].delete(onChange);\n };\n }\n\n protected setState<K extends RealtimeStateKey>(\n key: K,\n value: RealtimeState[K],\n ): void {\n this.state = { ...this.state, [key]: value };\n this.callbacks[key].forEach(callback => callback());\n }\n\n protected pushMessage(message: UIMessage): void {\n this.state = {\n ...this.state,\n messages: [...this.state.messages, message],\n };\n this.callbacks.messages.forEach(callback => callback());\n }\n\n protected updateMessages(\n updater: (messages: UIMessage[]) => UIMessage[],\n ): void {\n this.state = {\n ...this.state,\n messages: updater(this.state.messages),\n };\n this.callbacks.messages.forEach(callback => callback());\n }\n\n protected pushEvent(event: RealtimeServerEvent): void {\n const nextEvents = [...this.state.events, event];\n this.state = {\n ...this.state,\n events:\n nextEvents.length > this.maxEvents\n ? nextEvents.slice(-this.maxEvents)\n : nextEvents,\n };\n this.callbacks.events.forEach(callback => callback());\n }\n}\n\ntype UseRealtimeReturn = {\n status: RealtimeStatus;\n messages: UIMessage[];\n events: RealtimeServerEvent[];\n isCapturing: boolean;\n isPlaying: boolean;\n\n connect: () => Promise<void>;\n disconnect: () => void;\n addToolOutput: (callId: string, result: unknown) => void;\n sendEvent: RealtimeStore['sendEvent'];\n sendTextMessage: (text: string) => void;\n sendAudio: (base64Audio: string) => void;\n commitAudio: () => void;\n clearAudioBuffer: () => void;\n requestResponse: (options?: { modalities?: string[] }) => void;\n cancelResponse: () => void;\n startAudioCapture: (stream: MediaStream) => void;\n stopAudioCapture: () => void;\n stopPlayback: () => void;\n};\n\nfunction useRealtime(options: UseRealtimeOptions): UseRealtimeReturn {\n const callbacksRef = useRef({\n onToolCall: options.onToolCall,\n onEvent: options.onEvent,\n onError: options.onError,\n });\n callbacksRef.current = {\n onToolCall: options.onToolCall,\n onEvent: options.onEvent,\n onError: options.onError,\n };\n\n const realtimeRef = useRef<{\n store: RealtimeStore;\n key: RealtimeStoreKey;\n } | null>(null);\n\n let realtimeEntry = realtimeRef.current;\n\n if (\n realtimeEntry == null ||\n shouldCreateRealtimeStore(realtimeEntry.key, options)\n ) {\n realtimeEntry = {\n store: new RealtimeStore({\n ...options,\n onToolCall: (...args) => callbacksRef.current.onToolCall?.(...args),\n onEvent: (...args) => callbacksRef.current.onEvent?.(...args),\n onError: (...args) => callbacksRef.current.onError?.(...args),\n }),\n key: getRealtimeStoreKey(options),\n };\n realtimeRef.current = realtimeEntry;\n } else {\n realtimeEntry.key = getRealtimeStoreKey(options);\n }\n\n const rt = realtimeEntry.store;\n\n const status = useSyncExternalStore(\n useCallback(cb => rt.subscribe('status', cb), [rt]),\n () => rt.status,\n () => rt.status,\n );\n\n const messages = useSyncExternalStore(\n useCallback(cb => rt.subscribe('messages', cb), [rt]),\n () => rt.messages,\n () => rt.messages,\n );\n\n const events = useSyncExternalStore(\n useCallback(cb => rt.subscribe('events', cb), [rt]),\n () => rt.events,\n () => rt.events,\n );\n\n const isCapturing = useSyncExternalStore(\n useCallback(cb => rt.subscribe('isCapturing', cb), [rt]),\n () => rt.isCapturing,\n () => rt.isCapturing,\n );\n\n const isPlaying = useSyncExternalStore(\n useCallback(cb => rt.subscribe('isPlaying', cb), [rt]),\n () => rt.isPlaying,\n () => rt.isPlaying,\n );\n\n useEffect(() => {\n return () => rt.dispose();\n }, [rt]);\n\n return {\n status,\n messages,\n events,\n isCapturing,\n isPlaying,\n connect: rt.connect.bind(rt),\n disconnect: rt.disconnect.bind(rt),\n addToolOutput: rt.addToolOutput.bind(rt),\n sendEvent: rt.sendEvent.bind(rt),\n sendTextMessage: rt.sendTextMessage.bind(rt),\n sendAudio: rt.sendAudio.bind(rt),\n commitAudio: rt.commitAudio.bind(rt),\n clearAudioBuffer: rt.clearAudioBuffer.bind(rt),\n requestResponse: rt.requestResponse.bind(rt),\n cancelResponse: rt.cancelResponse.bind(rt),\n startAudioCapture: rt.startAudioCapture.bind(rt),\n stopAudioCapture: rt.stopAudioCapture.bind(rt),\n stopPlayback: rt.stopPlayback.bind(rt),\n };\n}\n\nexport const experimental_useRealtime = useRealtime;\n\nexport type {\n RealtimeStatus as Experimental_RealtimeStatus,\n UseRealtimeOptions as Experimental_UseRealtimeOptions,\n UseRealtimeReturn as Experimental_UseRealtimeReturn,\n};\n","import type { MCPAppResource } from '@ai-sdk/mcp';\nimport { useEffect, useState } from 'react';\nimport { MCPAppFrame } from './app-frame';\nimport type { MCPAppMetadata, MCPAppRendererProps } from './types';\nimport { getMCPAppFromToolPart } from './utils';\n\ntype LoadedResourceState = {\n resourceUri: string;\n resource?: MCPAppResource;\n error?: Error;\n};\n\nfunction getToolPartOutput(part: MCPAppRendererProps['part']): unknown {\n return part.state === 'output-available' ? part.output : undefined;\n}\n\nfunction getToolPartInput(part: MCPAppRendererProps['part']): unknown {\n return part.state === 'input-available' || part.state === 'output-available'\n ? part.input\n : undefined;\n}\n\nexport function MCPAppRenderer({\n part,\n sandbox,\n resource: resourceProp,\n loadResource,\n handlers,\n hostInfo,\n hostContext,\n fallback = null,\n}: MCPAppRendererProps) {\n const app = getMCPAppFromToolPart(part);\n const [cachedApp, setCachedApp] = useState<MCPAppMetadata>();\n const [loadedResource, setLoadedResource] = useState<LoadedResourceState>();\n\n useEffect(() => {\n if (app != null) {\n setCachedApp(previous =>\n previous?.resourceUri === app.resourceUri ? previous : app,\n );\n }\n }, [app?.resourceUri]);\n\n const appForRender = app ?? cachedApp;\n\n useEffect(() => {\n if (appForRender == null || resourceProp != null || loadResource == null) {\n return;\n }\n\n let cancelled = false;\n const resourceUri = appForRender.resourceUri;\n\n loadResource(appForRender)\n .then(resource => {\n if (!cancelled) {\n setLoadedResource({ resourceUri, resource });\n }\n })\n .catch(error => {\n if (!cancelled) {\n setLoadedResource({\n resourceUri,\n error: error instanceof Error ? error : new Error(String(error)),\n });\n }\n });\n\n return () => {\n cancelled = true;\n };\n }, [appForRender?.resourceUri, loadResource, resourceProp]);\n\n const loadedResourceForApp =\n loadedResource?.resourceUri === appForRender?.resourceUri\n ? loadedResource\n : undefined;\n const resource = resourceProp ?? loadedResourceForApp?.resource;\n const error = resourceProp == null ? loadedResourceForApp?.error : undefined;\n\n if (appForRender == null || error != null || resource == null) {\n return fallback;\n }\n\n return (\n <MCPAppFrame\n app={appForRender}\n resource={resource}\n input={getToolPartInput(part)}\n output={getToolPartOutput(part)}\n sandbox={sandbox}\n handlers={handlers}\n hostInfo={hostInfo}\n hostContext={hostContext}\n />\n );\n}\n","import { useEffect, useMemo, useRef } from 'react';\nimport { MCPAppBridge } from './bridge';\nimport {\n MCP_APP_DEFAULT_INNER_SANDBOX,\n MCP_APP_DEFAULT_OUTER_SANDBOX,\n getMCPAppAllowAttribute,\n getMCPAppCSP,\n} from './sandbox';\nimport type { MCPAppFrameProps } from './types';\nimport { normalizeMCPAppToolResult } from './utils';\n\n/**\n * Derives the concrete origin of the sandbox proxy from its URL, so outbound\n * postMessage targets a specific origin instead of `'*'` and inbound messages\n * can be origin-checked. The proxy must be served from a stable, concrete\n * origin (the default outer sandbox keeps `allow-same-origin`). Falls back to\n * the host origin on a malformed URL, never `'*'`.\n */\nfunction deriveTargetOrigin(url: string): string {\n const location = typeof window !== 'undefined' ? window.location : undefined;\n try {\n return new URL(url, location?.href).origin;\n } catch {\n return location?.origin ?? 'null';\n }\n}\n\nfunction sendToolState({\n bridge,\n input,\n output,\n}: {\n bridge?: MCPAppBridge;\n input: unknown;\n output: unknown;\n}) {\n if (bridge == null) {\n return;\n }\n\n if (input !== undefined) {\n bridge.sendToolInput(input);\n }\n\n if (output !== undefined) {\n bridge.sendToolResult(normalizeMCPAppToolResult(output));\n }\n}\n\nexport function MCPAppFrame({\n app,\n resource,\n input,\n output,\n sandbox,\n handlers,\n hostInfo,\n hostContext,\n}: MCPAppFrameProps) {\n const iframeRef = useRef<HTMLIFrameElement>(null);\n const bridgeRef = useRef<MCPAppBridge | undefined>(undefined);\n const inputRef = useRef(input);\n const outputRef = useRef(output);\n const hostContextRef = useRef(hostContext);\n const initializedRef = useRef(false);\n inputRef.current = input;\n outputRef.current = output;\n hostContextRef.current = hostContext;\n const sandboxUrl = String(sandbox.url);\n const targetOrigin = sandbox.targetOrigin ?? deriveTargetOrigin(sandboxUrl);\n const resourceCSP = getMCPAppCSP(resource.meta?.csp);\n const resourceAllow = getMCPAppAllowAttribute(\n resource.meta?.permissions,\n sandbox.allowedPermissions,\n );\n const innerSandbox = sandbox.innerSandbox ?? MCP_APP_DEFAULT_INNER_SANDBOX;\n const bridgeHandlers = useMemo(\n () => ({\n ...handlers,\n onInitialized: () => {\n initializedRef.current = true;\n handlers?.onInitialized?.();\n sendToolState({\n bridge: bridgeRef.current,\n input: inputRef.current,\n output: outputRef.current,\n });\n },\n }),\n [handlers],\n );\n const bridgeHandlersRef = useRef(bridgeHandlers);\n bridgeHandlersRef.current = bridgeHandlers;\n\n useEffect(() => {\n const iframe = iframeRef.current;\n const targetWindow = iframe?.contentWindow;\n if (targetWindow == null) {\n return;\n }\n\n initializedRef.current = false;\n\n const bridge = new MCPAppBridge({\n targetWindow,\n targetOrigin,\n handlers: bridgeHandlersRef.current,\n hostInfo,\n hostContext: hostContextRef.current,\n });\n bridgeRef.current = bridge;\n\n const onMessage = (event: MessageEvent) => {\n // Only handle messages from the proxy window and expected origin.\n if (!bridge.acceptsEvent(event)) {\n return;\n }\n\n if (\n event.data?.jsonrpc === '2.0' &&\n event.data.method === 'ui/notifications/sandbox-proxy-ready'\n ) {\n bridge.sendSandboxResourceReady({\n html: resource.html,\n csp: resourceCSP,\n sandbox: innerSandbox,\n allow: resourceAllow,\n });\n return;\n }\n\n bridge.handleMessage(event);\n };\n\n window.addEventListener('message', onMessage);\n\n return () => {\n initializedRef.current = false;\n window.removeEventListener('message', onMessage);\n void bridge.teardownResource().catch(() => {});\n bridge.close();\n bridgeRef.current = undefined;\n };\n }, [\n hostInfo,\n innerSandbox,\n resource.html,\n resourceAllow,\n resourceCSP,\n sandboxUrl,\n targetOrigin,\n ]);\n\n useEffect(() => {\n bridgeRef.current?.setHandlers(bridgeHandlers);\n }, [bridgeHandlers]);\n\n useEffect(() => {\n if (hostContext != null) {\n bridgeRef.current?.setHostContext(hostContext);\n }\n }, [hostContext]);\n\n useEffect(() => {\n if (initializedRef.current && input !== undefined) {\n bridgeRef.current?.sendToolInput(input);\n }\n }, [input]);\n\n useEffect(() => {\n if (initializedRef.current && output !== undefined) {\n bridgeRef.current?.sendToolResult(normalizeMCPAppToolResult(output));\n }\n }, [output]);\n\n return (\n <iframe\n ref={iframeRef}\n title=\"MCP App\"\n aria-label={sandbox.title ?? app.resourceUri}\n src={sandboxUrl}\n className={sandbox.className}\n style={sandbox.style}\n // Permissions Policy is hierarchical: the outer frame must delegate a\n // feature for the proxy to re-delegate it to the inner app frame.\n allow={resourceAllow}\n sandbox={sandbox.outerSandbox ?? MCP_APP_DEFAULT_OUTER_SANDBOX}\n />\n );\n}\n","import { isJSONObject } from '@ai-sdk/provider';\nimport type {\n MCPAppBridgeHandlers,\n MCPAppHostContext,\n MCPAppJsonRpcMessage,\n MCPAppJsonRpcNotification,\n MCPAppJsonRpcRequest,\n MCPAppJsonRpcResponse,\n MCPAppToolCallParams,\n} from './types';\n\nconst MCP_APP_PROTOCOL_VERSION = '2026-01-26';\n\n/**\n * Checks whether an iframe message looks like a JSON-RPC 2.0 message.\n */\nfunction isJsonRpcMessage(value: unknown): value is MCPAppJsonRpcMessage {\n return (\n value != null &&\n typeof value === 'object' &&\n !Array.isArray(value) &&\n 'jsonrpc' in value &&\n value.jsonrpc === '2.0'\n );\n}\n\n/**\n * Checks whether a JSON-RPC message expects a response.\n */\nfunction isRequest(\n message: MCPAppJsonRpcMessage,\n): message is MCPAppJsonRpcRequest {\n return 'method' in message && 'id' in message;\n}\n\n/**\n * Checks whether a JSON-RPC message is a fire-and-forget notification.\n */\nfunction isNotification(\n message: MCPAppJsonRpcMessage,\n): message is MCPAppJsonRpcNotification {\n return 'method' in message && !('id' in message);\n}\n\n/**\n * Normalizes unknown thrown values into an `Error`.\n */\nfunction toError(error: unknown): Error {\n return error instanceof Error ? error : new Error(String(error));\n}\n\n/**\n * Validates the params for app-initiated `tools/call` requests.\n */\nfunction assertToolCallParams(params: unknown): MCPAppToolCallParams {\n if (!isJSONObject(params) || typeof params.name !== 'string') {\n throw new Error('Invalid tools/call params');\n }\n\n return {\n name: params.name,\n arguments: isJSONObject(params.arguments) ? params.arguments : undefined,\n };\n}\n\n/**\n * Validates `resources/read` params and limits reads to `ui://` app resources.\n */\nfunction assertResourceReadParams(params: unknown): { uri: string } {\n if (!isJSONObject(params) || typeof params.uri !== 'string') {\n throw new Error('Invalid resources/read params');\n }\n if (!params.uri.startsWith('ui://')) {\n throw new Error(\n `resources/read is limited to ui:// resources: ${params.uri}`,\n );\n }\n return { uri: params.uri };\n}\n\n/**\n * Validates `ui/open-link` params and allows only `https:`/`http:`/`mailto:`\n * URLs.\n */\nfunction assertOpenLinkParams(params: unknown): { url: string } {\n if (!isJSONObject(params) || typeof params.url !== 'string') {\n throw new Error('Invalid ui/open-link params');\n }\n\n let scheme: string;\n try {\n scheme = new URL(params.url).protocol;\n } catch {\n throw new Error(`Invalid ui/open-link url: ${params.url}`);\n }\n\n if (scheme !== 'https:' && scheme !== 'http:' && scheme !== 'mailto:') {\n throw new Error(`Disallowed ui/open-link scheme: ${scheme}`);\n }\n\n return { url: params.url };\n}\n\n/**\n * Validates params for `ui/request-display-mode`.\n */\nfunction assertDisplayModeParams(params: unknown): {\n mode: 'inline' | 'fullscreen' | 'pip';\n} {\n if (\n !isJSONObject(params) ||\n (params.mode !== 'inline' &&\n params.mode !== 'fullscreen' &&\n params.mode !== 'pip')\n ) {\n throw new Error('Invalid ui/request-display-mode params');\n }\n return { mode: params.mode };\n}\n\n/**\n * Host-side JSON-RPC bridge for one MCP App iframe.\n *\n * It handles the MCP Apps initialization handshake, sends tool input/result\n * notifications to the iframe, and proxies allowed iframe requests through\n * host-provided callbacks.\n *\n * @example\n * ```ts\n * const bridge = new MCPAppBridge({\n * targetWindow: iframe.contentWindow!,\n * handlers: {\n * allowedTools: ['refreshDashboardData'],\n * callTool: params => client.callTool(params),\n * },\n * });\n *\n * window.addEventListener('message', event => bridge.handleMessage(event));\n * bridge.sendToolInput({ topic: 'usage' });\n * ```\n */\nexport class MCPAppBridge {\n private initialized = false;\n private pendingNotifications: MCPAppJsonRpcNotification[] = [];\n private nextRequestId = 0;\n private pendingResponses = new Map<\n string | number,\n {\n resolve: (value: unknown) => void;\n reject: (error: Error) => void;\n }\n >();\n\n constructor({\n targetWindow,\n targetOrigin = '*',\n handlers = {},\n hostInfo = { name: 'ai-sdk-react', version: '1.0.0' },\n hostContext = { displayMode: 'inline' },\n }: {\n targetWindow: Window;\n targetOrigin?: string;\n handlers?: MCPAppBridgeHandlers;\n hostInfo?: { name: string; version: string };\n hostContext?: MCPAppHostContext;\n }) {\n this.targetWindow = targetWindow;\n this.targetOrigin = targetOrigin;\n this.handlers = handlers;\n this.hostInfo = hostInfo;\n this.hostContext = hostContext;\n }\n\n private targetWindow: Window;\n private targetOrigin: string;\n private handlers: MCPAppBridgeHandlers;\n private hostInfo: { name: string; version: string };\n private hostContext: MCPAppHostContext;\n\n /**\n * Replaces the callbacks used to serve iframe requests.\n */\n setHandlers(handlers: MCPAppBridgeHandlers): void {\n this.handlers = handlers;\n }\n\n /**\n * Updates host context and notifies the iframe after initialization.\n *\n * @example\n * ```ts\n * bridge.setHostContext({ theme: 'dark', displayMode: 'inline' });\n * ```\n */\n setHostContext(hostContext: MCPAppHostContext): void {\n this.hostContext = hostContext;\n this.sendNotification({\n method: 'ui/notifications/host-context-changed',\n params: hostContext,\n });\n }\n\n /**\n * Whether a `message` event came from the expected proxy window and origin.\n * The origin check is skipped only when `targetOrigin` is the `'*'` default.\n * Callers that intercept events before {@link handleMessage} share this check.\n */\n acceptsEvent(event: MessageEvent): boolean {\n return (\n event.source === this.targetWindow &&\n (this.targetOrigin === '*' || event.origin === this.targetOrigin)\n );\n }\n\n /**\n * Processes one `message` event from the sandbox proxy iframe.\n */\n handleMessage(event: MessageEvent): void {\n if (!this.acceptsEvent(event) || !isJsonRpcMessage(event.data)) {\n return;\n }\n\n const message = event.data;\n\n if ('result' in message || 'error' in message) {\n this.handleResponse(message);\n return;\n }\n\n if (isRequest(message)) {\n void this.handleRequest(message);\n return;\n }\n\n if (isNotification(message)) {\n this.handleNotification(message);\n }\n }\n\n /**\n * Sends app HTML and sandbox settings to the sandbox proxy.\n */\n sendSandboxResourceReady(params: unknown): void {\n this.post({\n jsonrpc: '2.0',\n method: 'ui/notifications/sandbox-resource-ready',\n params,\n });\n }\n\n /**\n * Sends final tool arguments to the MCP App.\n */\n sendToolInput(input: unknown): void {\n this.sendNotification({\n method: 'ui/notifications/tool-input',\n params: { arguments: input },\n });\n }\n\n /**\n * Sends a completed MCP tool result to the MCP App.\n */\n sendToolResult(result: unknown): void {\n this.sendNotification({\n method: 'ui/notifications/tool-result',\n params: result,\n });\n }\n\n /**\n * Notifies the MCP App that the related tool call was cancelled.\n */\n sendToolCancelled(reason?: string): void {\n this.sendNotification({\n method: 'ui/notifications/tool-cancelled',\n params: reason != null ? { reason } : {},\n });\n }\n\n /**\n * Requests graceful teardown before the host removes the iframe.\n */\n teardownResource(): Promise<unknown> {\n return this.request('ui/resource-teardown', {});\n }\n\n /**\n * Rejects pending bridge requests and clears queued notifications.\n */\n close(): void {\n for (const pending of this.pendingResponses.values()) {\n pending.reject(new Error('MCP App bridge closed'));\n }\n this.pendingResponses.clear();\n this.pendingNotifications = [];\n }\n\n /**\n * Resolves or rejects a host-initiated request when the iframe responds.\n */\n private handleResponse(response: MCPAppJsonRpcResponse): void {\n const pending = this.pendingResponses.get(response.id);\n if (pending == null) {\n return;\n }\n\n this.pendingResponses.delete(response.id);\n\n if (response.error != null) {\n pending.reject(new Error(response.error.message));\n } else {\n pending.resolve(response.result);\n }\n }\n\n /**\n * Runs a handler for an iframe request and posts the JSON-RPC response.\n */\n private async handleRequest(request: MCPAppJsonRpcRequest): Promise<void> {\n try {\n const result = await this.getRequestResult(request);\n this.post({ jsonrpc: '2.0', id: request.id, result });\n } catch (error) {\n const normalizedError = toError(error);\n this.handlers.onError?.(normalizedError);\n this.post({\n jsonrpc: '2.0',\n id: request.id,\n error: { code: -32603, message: normalizedError.message },\n });\n }\n }\n\n /**\n * Maps supported iframe request methods to host callbacks.\n */\n private async getRequestResult(\n request: MCPAppJsonRpcRequest,\n ): Promise<unknown> {\n switch (request.method) {\n case 'ui/initialize':\n return {\n protocolVersion: MCP_APP_PROTOCOL_VERSION,\n hostCapabilities: {\n ...(this.handlers.callTool != null ? { serverTools: {} } : {}),\n ...(this.handlers.readResource != null\n ? { serverResources: {} }\n : {}),\n ...(this.handlers.onLog != null ? { logging: {} } : {}),\n },\n hostInfo: this.hostInfo,\n hostContext: this.hostContext,\n };\n\n case 'tools/call': {\n if (this.handlers.callTool == null) {\n throw new Error('No tools/call handler configured');\n }\n const params = assertToolCallParams(request.params);\n // Deny-by-default: the (untrusted) MCP App may only invoke tools the\n // host has explicitly allow-listed. Omitting `allowedTools` exposes no\n // tools, rather than forwarding every requested tool to `callTool`.\n if (\n this.handlers.allowedTools == null ||\n !this.handlers.allowedTools.includes(params.name)\n ) {\n throw new Error(`Tool is not app-visible: ${params.name}`);\n }\n return this.handlers.callTool(params);\n }\n\n case 'resources/read':\n if (this.handlers.readResource == null) {\n throw new Error('No resources/read handler configured');\n }\n return this.handlers.readResource(\n assertResourceReadParams(request.params),\n );\n\n case 'resources/list':\n if (this.handlers.listResources == null) {\n throw new Error('No resources/list handler configured');\n }\n return this.handlers.listResources(request.params);\n\n case 'ui/open-link':\n if (this.handlers.openLink == null) {\n throw new Error('No ui/open-link handler configured');\n }\n return this.handlers.openLink(assertOpenLinkParams(request.params));\n\n case 'ui/message':\n return this.handlers.sendMessage?.(request.params) ?? {};\n\n case 'ui/update-model-context':\n return this.handlers.updateModelContext?.(request.params) ?? {};\n\n case 'ui/request-display-mode':\n return (\n this.handlers.requestDisplayMode?.(\n assertDisplayModeParams(request.params),\n ) ?? { mode: this.hostContext.displayMode ?? 'inline' }\n );\n\n default:\n throw new Error(`Unsupported MCP App method: ${request.method}`);\n }\n }\n\n /**\n * Handles iframe lifecycle and telemetry notifications.\n */\n private handleNotification(notification: MCPAppJsonRpcNotification): void {\n switch (notification.method) {\n case 'ui/notifications/initialized':\n this.initialized = true;\n this.flushNotifications();\n this.handlers.onInitialized?.();\n break;\n case 'ui/notifications/size-changed':\n this.handlers.onSizeChange?.(\n notification.params as { width?: number; height?: number },\n );\n break;\n case 'ui/notifications/request-teardown':\n this.handlers.onRequestTeardown?.(notification.params);\n break;\n case 'notifications/message':\n this.handlers.onLog?.(notification.params);\n break;\n }\n }\n\n /**\n * Sends a host-to-iframe notification, queueing it until app initialization.\n */\n private sendNotification(\n notification: Omit<MCPAppJsonRpcNotification, 'jsonrpc'>,\n ) {\n const message = { jsonrpc: '2.0' as const, ...notification };\n if (!this.initialized && !notification.method.includes('sandbox')) {\n this.pendingNotifications.push(message);\n return;\n }\n this.post(message);\n }\n\n /**\n * Sends notifications that were queued before `ui/notifications/initialized`.\n */\n private flushNotifications(): void {\n const notifications = this.pendingNotifications;\n this.pendingNotifications = [];\n for (const notification of notifications) {\n this.post(notification);\n }\n }\n\n /**\n * Sends a host-initiated JSON-RPC request to the iframe.\n */\n private request(method: string, params: unknown): Promise<unknown> {\n const id = this.nextRequestId++;\n this.post({ jsonrpc: '2.0', id, method, params });\n return new Promise((resolve, reject) => {\n this.pendingResponses.set(id, { resolve, reject });\n });\n }\n\n /**\n * Posts a JSON-RPC message to the sandbox proxy iframe.\n */\n private post(message: MCPAppJsonRpcMessage): void {\n this.targetWindow.postMessage(message, this.targetOrigin);\n }\n}\n","import type { MCPAppResourceCSP } from '@ai-sdk/mcp';\n\n// CSP source values come from the (untrusted) MCP server. Rather than\n// denylisting bad characters on the raw string (which an encoding like \"%3B\"\n// can slip past), canonicalize each value: parse it as an absolute URL so any\n// percent-encoding is decoded, keep only https/wss origins, then re-check the\n// decoded origin so a separator that decoded back into \";\" \",\" or whitespace\n// cannot split the directive.\nconst ALLOWED_CSP_SCHEMES = new Set(['https:', 'wss:']);\n\nfunction sanitizeCSPSources(sources?: string[]): string[] {\n const result: string[] = [];\n for (const source of sources ?? []) {\n if (typeof source !== 'string') {\n continue;\n }\n\n let origin: string;\n try {\n const url = new URL(source);\n // Reject non-https/wss, the empty host, and a bare \"*\" host (which would\n // match every origin and defeat the allowlist, like scheme-only \"https:\").\n if (\n !ALLOWED_CSP_SCHEMES.has(url.protocol) ||\n url.host.length === 0 ||\n url.host === '*'\n ) {\n continue;\n }\n origin = url.origin;\n } catch {\n continue;\n }\n\n // Drop separators that split the directive and quotes that could break out\n // of an HTML attribute the policy may be embedded in downstream.\n if (/[\"'`\\s;,]/.test(origin)) {\n continue;\n }\n\n result.push(origin);\n }\n return result;\n}\n\n/**\n * Default sandbox permissions for the outer sandbox proxy iframe.\n */\nexport const MCP_APP_DEFAULT_OUTER_SANDBOX =\n 'allow-scripts allow-same-origin allow-forms';\n\n/**\n * Default sandbox permissions for the inner iframe that runs app HTML.\n */\nexport const MCP_APP_DEFAULT_INNER_SANDBOX = 'allow-scripts allow-forms';\n\n/**\n * Converts MCP App CSP metadata into a Content-Security-Policy string.\n *\n * The returned value is meant to be passed to a sandbox proxy, which can apply\n * it to the inner iframe document.\n *\n * @example\n * ```ts\n * const csp = getMCPAppCSP({\n * connectDomains: ['https://api.example.com'],\n * resourceDomains: ['https://cdn.example.com'],\n * });\n * ```\n */\nexport function getMCPAppCSP(csp?: MCPAppResourceCSP): string | undefined {\n if (csp == null) {\n return undefined;\n }\n\n const connectSrc = [\"'self'\", ...sanitizeCSPSources(csp.connectDomains)];\n const imgSrc = [\n \"'self'\",\n 'data:',\n ...sanitizeCSPSources(csp.resourceDomains),\n ];\n const frameSrc = [\"'self'\", ...sanitizeCSPSources(csp.frameDomains)];\n\n return [\n \"default-src 'none'\",\n \"base-uri 'none'\",\n \"form-action 'none'\",\n \"script-src 'unsafe-inline'\",\n \"style-src 'unsafe-inline'\",\n `connect-src ${connectSrc.join(' ')}`,\n `img-src ${imgSrc.join(' ')}`,\n `font-src ${imgSrc.join(' ')}`,\n `frame-src ${frameSrc.join(' ')}`,\n ].join('; ');\n}\n\n/**\n * A permission an MCP App may request and a host may allow.\n */\nexport type MCPAppPermission =\n | 'camera'\n | 'microphone'\n | 'geolocation'\n | 'clipboardWrite';\n\nconst MCP_APP_PERMISSION_FEATURES: Record<MCPAppPermission, string> = {\n camera: 'camera',\n microphone: 'microphone',\n geolocation: 'geolocation',\n clipboardWrite: 'clipboard-write',\n};\n\n/**\n * Converts MCP App permission metadata into an iframe `allow` attribute.\n *\n * Deny-by-default: a capability is granted only when it is both requested in\n * `permissions` and present in the host `allowedPermissions` allowlist.\n * Omitting the allowlist grants nothing, mirroring `allowedTools` in the bridge.\n *\n * @example\n * ```ts\n * const allow = getMCPAppAllowAttribute(\n * { microphone: {}, camera: {} },\n * ['microphone'],\n * );\n * // \"microphone\" — camera requested by server but not host-allowed\n * ```\n */\nexport function getMCPAppAllowAttribute(\n permissions?: Record<string, unknown>,\n allowedPermissions?: MCPAppPermission[],\n): string | undefined {\n if (permissions == null || allowedPermissions == null) {\n return undefined;\n }\n\n const allow = allowedPermissions\n .filter(permission => Boolean(permissions[permission]))\n .map(permission => MCP_APP_PERMISSION_FEATURES[permission]);\n\n return allow.length > 0 ? allow.join('; ') : undefined;\n}\n","import { isJSONObject } from '@ai-sdk/provider';\nimport type { MCPAppMetadata, MCPAppRendererProps } from './types';\n\n/**\n * Extracts MCP App metadata from an AI SDK tool UI part.\n *\n * @example\n * ```ts\n * const app = getMCPAppFromToolPart({\n * type: 'dynamic-tool',\n * toolName: 'showDashboard',\n * toolCallId: 'call-1',\n * state: 'input-available',\n * input: { topic: 'usage' },\n * toolMetadata: {\n * app: {\n * resourceUri: 'ui://example/dashboard',\n * mimeType: 'text/html;profile=mcp-app',\n * },\n * },\n * });\n * // { resourceUri: 'ui://example/dashboard', mimeType: 'text/html;profile=mcp-app' }\n * ```\n */\nexport function getMCPAppFromToolPart(\n part: MCPAppRendererProps['part'],\n): MCPAppMetadata | undefined {\n const rawAppMetadata = part.toolMetadata?.app;\n const appMetadata = isJSONObject(rawAppMetadata) ? rawAppMetadata : undefined;\n\n if (\n appMetadata == null ||\n appMetadata.mimeType !== 'text/html;profile=mcp-app' ||\n typeof appMetadata.resourceUri !== 'string' ||\n !appMetadata.resourceUri.startsWith('ui://') ||\n (appMetadata.visibility != null &&\n (!Array.isArray(appMetadata.visibility) ||\n appMetadata.visibility.some(\n value => value !== 'model' && value !== 'app',\n )))\n ) {\n return undefined;\n }\n\n return appMetadata as MCPAppMetadata;\n}\n\n/**\n * Converts an AI SDK tool output into the MCP Apps tool-result shape.\n *\n * MCP Apps expect tool results to have `content` and optional\n * `structuredContent`. MCP tools already return that shape, but typed AI SDK\n * tools may return only structured data. This helper wraps structured-only\n * outputs so the iframe can receive a valid tool result notification.\n *\n * @example\n * ```ts\n * normalizeMCPAppToolResult({ cards: [] });\n * // { content: [], structuredContent: { cards: [] } }\n * ```\n */\nexport function normalizeMCPAppToolResult(output: unknown): {\n content: unknown[];\n structuredContent?: unknown;\n isError?: boolean;\n} {\n if (output != null && typeof output === 'object' && 'content' in output) {\n return output as {\n content: unknown[];\n structuredContent?: unknown;\n isError?: boolean;\n };\n }\n\n return {\n content: [],\n structuredContent: output,\n };\n}\n","import type { FlexibleSchema } from '@ai-sdk/provider-utils';\nimport {\n useObject,\n type UseObjectHelpers,\n type UseObjectOptions,\n} from './use-object';\n\nexport * from './use-chat';\nexport { Chat } from './chat.react';\nexport * from './use-completion';\nexport * from './use-object';\nexport * from './use-realtime';\nexport * from './mcp-apps';\n\n// deprecated aliases\n// note: declared here (instead of export aliases) so that the `@deprecated`\n// tags are preserved in the bundled type declarations\n\n/**\n * @deprecated Use `useObject` instead.\n */\nexport const experimental_useObject = useObject;\n\n/**\n * @deprecated Use `UseObjectOptions` instead.\n */\nexport type Experimental_UseObjectOptions<\n SCHEMA extends FlexibleSchema,\n RESULT,\n> = UseObjectOptions<SCHEMA, RESULT>;\n\n/**\n * @deprecated Use `UseObjectHelpers` instead.\n */\nexport type Experimental_UseObjectHelpers<RESULT, INPUT> = UseObjectHelpers<\n RESULT,\n INPUT\n>;\n"],"mappings":"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","names":["fetch","error","useCallback","useRef","throttle","useRef","useCallback","useCallback","useEffect","useId","useRef","useState","useSWR","fetch","useId","useSWR","useState","useRef","useEffect","useCallback","completion","useCallback","useEffect","useRef","useSyncExternalStore","useEffect","useState","useEffect","useMemo","useRef","resolve","isJSONObject","useRef","useMemo","_a","useEffect","jsx","useState","useEffect","resource","error"]}
1
+ {"version":3,"sources":["../src/use-object.ts","../src/use-chat.ts","../src/chat.react.ts","../src/throttle.ts","../src/use-completion.ts","../src/use-realtime.ts","../src/mcp-apps/app-renderer.tsx","../src/mcp-apps/app-frame.tsx","../src/mcp-apps/bridge.ts","../src/mcp-apps/sandbox.ts","../src/mcp-apps/utils.ts","../src/index.ts"],"sourcesContent":["import {\n isAbortError,\n resolve,\n normalizeHeaders,\n safeValidateTypes,\n type FetchFunction,\n type FlexibleSchema,\n type InferSchema,\n type Resolvable,\n} from '@ai-sdk/provider-utils';\nimport {\n asSchema,\n isDeepEqualData,\n parsePartialJson,\n type DeepPartial,\n} from 'ai';\nimport { useCallback, useId, useRef, useState } from 'react';\nimport useSWR from 'swr';\n\n// use function to allow for mocking in tests:\nconst getOriginalFetch = () => fetch;\n\nexport type UseObjectOptions<SCHEMA extends FlexibleSchema, RESULT> = {\n /**\n * The API endpoint. It should stream JSON that matches the schema as chunked text.\n */\n api: string;\n\n /**\n * A schema that defines the shape of the complete object.\n */\n schema: SCHEMA;\n\n /**\n * An unique identifier. If not provided, a random one will be\n * generated. When provided, the `useObject` hook with the same `id` will\n * have shared states across components.\n */\n id?: string;\n\n /**\n * An optional value for the initial object.\n */\n initialValue?: DeepPartial<RESULT>;\n\n /**\n * Custom fetch implementation. You can use it as a middleware to intercept requests,\n * or to provide a custom fetch implementation for e.g. testing.\n */\n fetch?: FetchFunction;\n\n /**\n * Callback that is called when the stream has finished.\n */\n onFinish?: (event: {\n /**\n * The generated object (typed according to the schema).\n * Can be undefined if the final object does not match the schema.\n */\n object: RESULT | undefined;\n\n /**\n * Optional error object. This is e.g. a TypeValidationError when the final object does not match the schema.\n */\n error: Error | undefined;\n }) => Promise<void> | void;\n\n /**\n * Callback function to be called when an error is encountered.\n */\n onError?: (error: Error) => void;\n\n /**\n * Additional HTTP headers to be included in the request.\n * Can be a static object, a function that returns headers, or an async function\n * for dynamic auth tokens.\n */\n headers?: Resolvable<Record<string, string> | Headers>;\n\n /**\n * The credentials mode to be used for the fetch request.\n * Possible values are: 'omit', 'same-origin', 'include'.\n * Defaults to 'same-origin'.\n */\n credentials?: RequestCredentials;\n};\n\nexport type UseObjectHelpers<RESULT, INPUT> = {\n /**\n * Calls the API with the provided input as JSON body.\n */\n submit: (input: INPUT) => void;\n\n /**\n * The current value for the generated object. Updated as the API streams JSON chunks.\n */\n object: DeepPartial<RESULT> | undefined;\n\n /**\n * The error object of the API request if any.\n */\n error: Error | undefined;\n\n /**\n * Flag that indicates whether an API request is in progress.\n */\n isLoading: boolean;\n\n /**\n * Abort the current request immediately, keep the current partial object if any.\n */\n stop: () => void;\n\n /**\n * Clear the object state.\n */\n clear: () => void;\n};\n\nexport function useObject<\n SCHEMA extends FlexibleSchema,\n RESULT = InferSchema<SCHEMA>,\n INPUT = any,\n>({\n api,\n id,\n schema, // required, in the future we will use it for validation\n initialValue,\n fetch,\n onError,\n onFinish,\n headers,\n credentials,\n}: UseObjectOptions<SCHEMA, RESULT>): UseObjectHelpers<RESULT, INPUT> {\n // Generate an unique id if not provided.\n const hookId = useId();\n const completionId = id ?? hookId;\n\n // Store the completion state in SWR, using the completionId as the key to share states.\n const { data, mutate } = useSWR<DeepPartial<RESULT>>(\n [completionId, 'object'],\n null,\n { fallbackData: initialValue },\n );\n\n const [error, setError] = useState<undefined | Error>(undefined);\n const [isLoading, setIsLoading] = useState(false);\n\n // Abort controller to cancel the current API call.\n const abortControllerRef = useRef<AbortController | null>(null);\n\n const stop = useCallback(() => {\n try {\n abortControllerRef.current?.abort();\n } catch {\n } finally {\n setIsLoading(false);\n abortControllerRef.current = null;\n }\n }, []);\n\n const submit = async (input: INPUT) => {\n try {\n clearObject();\n\n setIsLoading(true);\n\n const abortController = new AbortController();\n abortControllerRef.current = abortController;\n\n // Resolve headers at request time (supports async functions for dynamic auth tokens)\n const resolvedHeaders = await resolve(headers);\n\n const actualFetch = fetch ?? getOriginalFetch();\n const response = await actualFetch(api, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...normalizeHeaders(resolvedHeaders),\n },\n credentials,\n signal: abortController.signal,\n body: JSON.stringify(input),\n });\n\n if (!response.ok) {\n throw new Error(\n (await response.text()) || 'Failed to fetch the response.',\n );\n }\n\n if (response.body == null) {\n throw new Error('The response body is empty.');\n }\n\n let accumulatedText = '';\n let latestObject: DeepPartial<RESULT> | undefined = undefined;\n\n await response.body.pipeThrough(new TextDecoderStream()).pipeTo(\n new WritableStream<string>({\n async write(chunk) {\n accumulatedText += chunk;\n\n const { value } = await parsePartialJson(accumulatedText);\n const currentObject = value as DeepPartial<RESULT>;\n\n if (!isDeepEqualData(latestObject, currentObject)) {\n latestObject = currentObject;\n\n mutate(currentObject);\n }\n },\n\n async close() {\n setIsLoading(false);\n abortControllerRef.current = null;\n\n if (onFinish != null) {\n const validationResult = await safeValidateTypes({\n value: latestObject,\n schema: asSchema(schema),\n });\n\n onFinish(\n validationResult.success\n ? { object: validationResult.value, error: undefined }\n : { object: undefined, error: validationResult.error },\n );\n }\n },\n }),\n );\n } catch (error) {\n if (isAbortError(error)) {\n return;\n }\n\n if (onError && error instanceof Error) {\n onError(error);\n }\n\n setIsLoading(false);\n setError(error instanceof Error ? error : new Error(String(error)));\n }\n };\n\n const clear = () => {\n stop();\n clearObject();\n };\n\n const clearObject = () => {\n setError(undefined);\n setIsLoading(false);\n mutate(undefined);\n };\n\n return {\n submit,\n object: data,\n error,\n isLoading,\n stop,\n clear,\n };\n}\n","import {\n type AbstractChat,\n type ChatInit,\n type ChatTransport,\n type CreateUIMessage,\n type UIMessage,\n DefaultChatTransport,\n} from 'ai';\nimport {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useSyncExternalStore,\n} from 'react';\nimport { Chat } from './chat.react';\n\nexport type { CreateUIMessage, UIMessage };\n\nexport type UseChatHelpers<UI_MESSAGE extends UIMessage> = {\n /**\n * The id of the chat.\n */\n readonly id: string;\n\n /**\n * Update the `messages` state locally. This is useful when you want to\n * edit the messages on the client, and then trigger the `reload` method\n * manually to regenerate the AI response.\n */\n setMessages: (\n messages: UI_MESSAGE[] | ((messages: UI_MESSAGE[]) => UI_MESSAGE[]),\n ) => void;\n\n error: Error | undefined;\n} & Pick<\n AbstractChat<UI_MESSAGE>,\n | 'sendMessage'\n | 'regenerate'\n | 'stop'\n | 'resumeStream'\n | 'addToolResult'\n | 'addToolOutput'\n | 'addToolApprovalResponse'\n | 'status'\n | 'messages'\n | 'clearError'\n>;\n\nexport type UseChatOptions<UI_MESSAGE extends UIMessage> = (\n | { chat: Chat<UI_MESSAGE> }\n | ChatInit<UI_MESSAGE>\n) & {\n /**\n * Custom throttle wait in ms for the chat messages and data updates.\n * Default is undefined, which disables throttling.\n */\n throttle?: number;\n\n /**\n * @deprecated Use `throttle` instead.\n */\n experimental_throttle?: number;\n\n /**\n * Whether to resume an ongoing chat generation stream.\n */\n resume?: boolean;\n};\n\nexport function useChat<UI_MESSAGE extends UIMessage = UIMessage>({\n throttle,\n experimental_throttle,\n resume = false,\n ...options\n}: UseChatOptions<UI_MESSAGE> = {}): UseChatHelpers<UI_MESSAGE> {\n const throttleWaitMs = throttle ?? experimental_throttle;\n // the Chat instance is created once and not recreated when options change,\n // so it would normally keep the callbacks/transport from the first render forever\n\n // keep latest values in a ref that is refreshed on every render,\n // and hand `Chat` stable wrappers that read from it to avoid stale closures\n const latestRef = useRef<\n Partial<\n Pick<\n ChatInit<UI_MESSAGE>,\n | 'onToolCall'\n | 'onData'\n | 'onFinish'\n | 'onError'\n | 'sendAutomaticallyWhen'\n | 'transport'\n >\n >\n >({});\n\n if (!('chat' in options)) {\n latestRef.current = {\n onToolCall: options.onToolCall,\n onData: options.onData,\n onFinish: options.onFinish,\n onError: options.onError,\n sendAutomaticallyWhen: options.sendAutomaticallyWhen,\n transport: options.transport,\n };\n }\n\n // resolve the latest transport and fallback to a lazily created default transport\n let defaultTransport: ChatTransport<UI_MESSAGE> | undefined;\n const getTransport = () =>\n latestRef.current.transport ??\n (defaultTransport ??= new DefaultChatTransport<UI_MESSAGE>());\n\n // give `Chat` stable wrappers that always read the latest values from `latestRef`\n const chatOptions: typeof options = {\n ...options,\n transport: {\n sendMessages: sendOptions => getTransport().sendMessages(sendOptions),\n reconnectToStream: reconnectOptions =>\n getTransport().reconnectToStream(reconnectOptions),\n },\n onToolCall: arg => latestRef.current.onToolCall?.(arg),\n onData: arg => latestRef.current.onData?.(arg),\n onFinish: arg => latestRef.current.onFinish?.(arg),\n onError: arg => latestRef.current.onError?.(arg),\n sendAutomaticallyWhen: arg =>\n latestRef.current.sendAutomaticallyWhen?.(arg) ?? false,\n };\n\n const chatKey = 'chat' in options ? options.chat : options.id;\n const { chat, isExternallyManaged } = useMemo(\n () => ({\n chat: 'chat' in options ? options.chat : new Chat(chatOptions),\n isExternallyManaged: 'chat' in options,\n }),\n [chatKey],\n );\n\n useEffect(() => {\n if (isExternallyManaged) {\n return;\n }\n\n return () => {\n void chat.stop();\n };\n }, [chat, isExternallyManaged]);\n\n const messagesSnapshot = useMemo(() => ({ messages: chat.messages }), [chat]);\n\n const subscribeToMessages = useCallback(\n (update: () => void) => {\n let isSubscribed = true;\n\n const updateMessages = () => {\n if (!isSubscribed) {\n return;\n }\n\n messagesSnapshot.messages = chat.messages;\n update();\n };\n\n const unsubscribe = chat['~registerMessagesCallback'](\n updateMessages,\n throttleWaitMs,\n );\n\n // Synchronize changes that may have happened between render and\n // subscription. useSyncExternalStore checks the snapshot after\n // subscribing and schedules a render when it changed.\n messagesSnapshot.messages = chat.messages;\n\n return () => {\n isSubscribed = false;\n unsubscribe();\n };\n },\n [chat, messagesSnapshot, throttleWaitMs],\n );\n\n const getMessagesSnapshot = useCallback(\n () => messagesSnapshot.messages,\n [messagesSnapshot],\n );\n\n const messages = useSyncExternalStore(\n subscribeToMessages,\n getMessagesSnapshot,\n getMessagesSnapshot,\n );\n\n const subscribeToStatus = useCallback(\n (update: () => void) =>\n chat['~registerStatusCallback'](() => {\n if (chat.status === 'ready' || chat.status === 'error') {\n // Publish the latest messages before the terminal status can render.\n messagesSnapshot.messages = chat.messages;\n }\n\n update();\n }),\n [chat, messagesSnapshot],\n );\n\n const getStatusSnapshot = useCallback(() => chat.status, [chat]);\n\n const status = useSyncExternalStore(\n subscribeToStatus,\n getStatusSnapshot,\n getStatusSnapshot,\n );\n\n const error = useSyncExternalStore(\n chat['~registerErrorCallback'],\n () => chat.error,\n () => chat.error,\n );\n\n const setMessages = useCallback(\n (\n messagesParam: UI_MESSAGE[] | ((messages: UI_MESSAGE[]) => UI_MESSAGE[]),\n ) => {\n if (typeof messagesParam === 'function') {\n messagesParam = messagesParam(chat.messages);\n }\n chat.messages = messagesParam;\n },\n [chat],\n );\n\n useEffect(() => {\n if (resume) {\n chat.resumeStream();\n }\n }, [resume, chat]);\n\n return {\n id: chat.id,\n messages,\n setMessages,\n sendMessage: chat.sendMessage,\n regenerate: chat.regenerate,\n clearError: chat.clearError,\n stop: chat.stop,\n error,\n resumeStream: chat.resumeStream,\n status,\n /**\n * @deprecated Use `addToolOutput` instead.\n */\n addToolResult: chat.addToolOutput,\n addToolOutput: chat.addToolOutput,\n addToolApprovalResponse: chat.addToolApprovalResponse,\n };\n}\n","import {\n AbstractChat,\n type ChatInit,\n type ChatState,\n type ChatStatus,\n type UIMessage,\n} from 'ai';\nimport { throttle } from './throttle';\n\nfunction cloneMetadata<METADATA>(metadata: METADATA): METADATA {\n if (Array.isArray(metadata)) {\n return [...metadata] as METADATA;\n }\n\n if (\n metadata != null &&\n typeof metadata === 'object' &&\n (Object.getPrototypeOf(metadata) === Object.prototype ||\n Object.getPrototypeOf(metadata) === null)\n ) {\n return { ...metadata } as METADATA;\n }\n\n return metadata;\n}\n\nclass ReactChatState<\n UI_MESSAGE extends UIMessage,\n> implements ChatState<UI_MESSAGE> {\n #messages: UI_MESSAGE[];\n #status: ChatStatus = 'ready';\n #error: Error | undefined = undefined;\n\n #messagesCallbacks = new Set<() => void>();\n #statusCallbacks = new Set<() => void>();\n #errorCallbacks = new Set<() => void>();\n\n constructor(initialMessages: UI_MESSAGE[] = []) {\n this.#messages = initialMessages;\n }\n\n get status(): ChatStatus {\n return this.#status;\n }\n\n set status(newStatus: ChatStatus) {\n this.#status = newStatus;\n this.#callStatusCallbacks();\n }\n\n get error(): Error | undefined {\n return this.#error;\n }\n\n set error(newError: Error | undefined) {\n this.#error = newError;\n this.#callErrorCallbacks();\n }\n\n get messages(): UI_MESSAGE[] {\n return this.#messages;\n }\n\n set messages(newMessages: UI_MESSAGE[]) {\n this.#messages = [...newMessages];\n this.#callMessagesCallbacks();\n }\n\n pushMessage = (message: UI_MESSAGE) => {\n this.#messages = this.#messages.concat(message);\n this.#callMessagesCallbacks();\n };\n\n popMessage = () => {\n this.#messages = this.#messages.slice(0, -1);\n this.#callMessagesCallbacks();\n };\n\n replaceMessage = (index: number, message: UI_MESSAGE) => {\n this.#messages = [\n ...this.#messages.slice(0, index),\n this.snapshot(message),\n ...this.#messages.slice(index + 1),\n ];\n this.#callMessagesCallbacks();\n };\n\n snapshot = <T>(value: T): T => {\n if (\n value == null ||\n typeof value !== 'object' ||\n !('parts' in value) ||\n !Array.isArray(value.parts)\n ) {\n return value;\n }\n\n const message = value as UI_MESSAGE;\n const snapshot = {\n ...message,\n parts: message.parts.map(part => ({ ...part })),\n };\n\n if ('metadata' in message) {\n snapshot.metadata = cloneMetadata(message.metadata);\n }\n\n return snapshot as T;\n };\n\n '~registerMessagesCallback' = (\n onChange: () => void,\n throttleWaitMs?: number,\n ): (() => void) => {\n const callback = throttleWaitMs\n ? throttle(onChange, throttleWaitMs)\n : onChange;\n this.#messagesCallbacks.add(callback);\n return () => {\n this.#messagesCallbacks.delete(callback);\n };\n };\n\n '~registerStatusCallback' = (onChange: () => void): (() => void) => {\n this.#statusCallbacks.add(onChange);\n return () => {\n this.#statusCallbacks.delete(onChange);\n };\n };\n\n '~registerErrorCallback' = (onChange: () => void): (() => void) => {\n this.#errorCallbacks.add(onChange);\n return () => {\n this.#errorCallbacks.delete(onChange);\n };\n };\n\n #callMessagesCallbacks = () => {\n this.#messagesCallbacks.forEach(callback => callback());\n };\n\n #callStatusCallbacks = () => {\n this.#statusCallbacks.forEach(callback => callback());\n };\n\n #callErrorCallbacks = () => {\n this.#errorCallbacks.forEach(callback => callback());\n };\n}\n\nexport class Chat<\n UI_MESSAGE extends UIMessage,\n> extends AbstractChat<UI_MESSAGE> {\n #state: ReactChatState<UI_MESSAGE>;\n\n constructor({ messages, ...init }: ChatInit<UI_MESSAGE>) {\n const state = new ReactChatState(messages);\n super({ ...init, state });\n this.#state = state;\n }\n\n '~registerMessagesCallback' = (\n onChange: () => void,\n throttleWaitMs?: number,\n ): (() => void) =>\n this.#state['~registerMessagesCallback'](onChange, throttleWaitMs);\n\n '~registerStatusCallback' = (onChange: () => void): (() => void) =>\n this.#state['~registerStatusCallback'](onChange);\n\n '~registerErrorCallback' = (onChange: () => void): (() => void) =>\n this.#state['~registerErrorCallback'](onChange);\n}\n","import throttleFunction from 'throttleit';\n\nexport function throttle<T extends (...args: any[]) => any>(\n fn: T,\n waitMs: number | undefined,\n): T {\n return waitMs != null ? throttleFunction(fn, waitMs) : fn;\n}\n","import {\n callCompletionApi,\n type CompletionRequestOptions,\n type UseCompletionOptions,\n} from 'ai';\nimport { useCallback, useEffect, useId, useRef, useState } from 'react';\nimport useSWR from 'swr';\nimport { throttle } from './throttle';\n\nexport type { UseCompletionOptions };\n\nexport type UseCompletionHelpers<BODY extends object = object> = {\n /** The current completion result */\n completion: string;\n /**\n * Send a new prompt to the API endpoint and update the completion state.\n */\n complete: (\n prompt: string,\n options?: CompletionRequestOptions<BODY>,\n ) => Promise<string | null | undefined>;\n /** The error object of the API request */\n error: undefined | Error;\n /**\n * Abort the current API request but keep the generated tokens.\n */\n stop: () => void;\n /**\n * Update the `completion` state locally.\n */\n setCompletion: (completion: string) => void;\n /** The current value of the input */\n input: string;\n /** setState-powered method to update the input value */\n setInput: React.Dispatch<React.SetStateAction<string>>;\n /**\n * An input/textarea-ready onChange handler to control the value of the input\n * @example\n * ```jsx\n * <input onChange={handleInputChange} value={input} />\n * ```\n */\n handleInputChange: (\n event:\n | React.ChangeEvent<HTMLInputElement>\n | React.ChangeEvent<HTMLTextAreaElement>,\n ) => void;\n\n /**\n * Form submission handler to automatically reset input and append a user message\n * @example\n * ```jsx\n * <form onSubmit={handleSubmit}>\n * <input onChange={handleInputChange} value={input} />\n * </form>\n * ```\n */\n handleSubmit: (event?: { preventDefault?: () => void }) => void;\n\n /** Whether the API request is in progress */\n isLoading: boolean;\n};\n\nexport function useCompletion<BODY extends object = object>({\n api = '/api/completion',\n id,\n initialCompletion = '',\n initialInput = '',\n credentials,\n headers,\n body,\n streamProtocol = 'data',\n fetch,\n onFinish,\n onError,\n throttle: throttleWait,\n experimental_throttle,\n}: UseCompletionOptions<NoInfer<BODY>> & {\n /**\n * Custom throttle wait in ms for the completion and data updates.\n * Default is undefined, which disables throttling.\n */\n throttle?: number;\n\n /**\n * @deprecated Use `throttle` instead.\n */\n experimental_throttle?: number;\n} = {}): UseCompletionHelpers<BODY> {\n const throttleWaitMs = throttleWait ?? experimental_throttle;\n // Generate an unique id for the completion if not provided.\n const hookId = useId();\n const completionId = id || hookId;\n\n // Store the completion state in SWR, using the completionId as the key to share states.\n const { data, mutate } = useSWR<string>([api, completionId], null, {\n fallbackData: initialCompletion,\n });\n\n const { data: isLoading = false, mutate: mutateLoading } = useSWR<boolean>(\n [completionId, 'loading'],\n null,\n );\n\n const [error, setError] = useState<undefined | Error>(undefined);\n const completion = data!;\n\n // Abort controller to cancel the current API call.\n const [abortController, setAbortController] =\n useState<AbortController | null>(null);\n\n const extraMetadataRef = useRef({\n credentials,\n headers,\n body,\n });\n\n useEffect(() => {\n extraMetadataRef.current = {\n credentials,\n headers,\n body,\n };\n }, [credentials, headers, body]);\n\n const triggerRequest = useCallback(\n async (prompt: string, options?: CompletionRequestOptions<BODY>) =>\n callCompletionApi({\n api,\n prompt,\n credentials: extraMetadataRef.current.credentials,\n headers: { ...extraMetadataRef.current.headers, ...options?.headers },\n body: {\n ...extraMetadataRef.current.body,\n ...options?.body,\n },\n streamProtocol,\n fetch,\n // throttle streamed ui updates:\n setCompletion: throttle(\n (completion: string) => mutate(completion, false),\n throttleWaitMs,\n ),\n setLoading: mutateLoading,\n setError,\n setAbortController,\n onFinish,\n onError,\n }),\n [\n mutate,\n mutateLoading,\n api,\n extraMetadataRef,\n setAbortController,\n onFinish,\n onError,\n setError,\n streamProtocol,\n fetch,\n throttleWaitMs,\n ],\n );\n\n const stop = useCallback(() => {\n if (abortController) {\n abortController.abort();\n setAbortController(null);\n }\n }, [abortController]);\n\n const setCompletion = useCallback(\n (completion: string) => {\n mutate(completion, false);\n },\n [mutate],\n );\n\n const complete = useCallback<UseCompletionHelpers<BODY>['complete']>(\n async (prompt, options) => {\n return triggerRequest(prompt, options);\n },\n [triggerRequest],\n );\n\n const [input, setInput] = useState(initialInput);\n\n const handleSubmit = useCallback(\n (event?: { preventDefault?: () => void }) => {\n event?.preventDefault?.();\n if (!input) {\n return;\n }\n\n const result = complete(input);\n setInput('');\n return result;\n },\n [input, complete, setInput],\n );\n\n const handleInputChange = useCallback(\n (e: any) => {\n setInput(e.target.value);\n },\n [setInput],\n );\n\n return {\n completion,\n complete,\n error,\n setCompletion,\n stop,\n input,\n setInput,\n handleInputChange,\n handleSubmit,\n isLoading,\n };\n}\n","import { secureJsonParse } from '@ai-sdk/provider-utils';\nimport {\n Experimental_AbstractRealtimeSession as AbstractRealtimeSession,\n type Experimental_RealtimeServerEvent as RealtimeServerEvent,\n type Experimental_RealtimeSessionOptions as RealtimeSessionOptions,\n type Experimental_RealtimeState as RealtimeState,\n type Experimental_RealtimeStatus as RealtimeStatus,\n type UIMessage,\n} from 'ai';\nimport {\n useCallback,\n useEffect,\n useInsertionEffect,\n useLayoutEffect,\n useMemo,\n useRef,\n useSyncExternalStore,\n} from 'react';\n\ntype UseRealtimeOptions = RealtimeSessionOptions;\n\ntype RealtimeStateKey = keyof RealtimeState;\n\nconst useIsomorphicLayoutEffect =\n typeof window === 'undefined' ? useEffect : useLayoutEffect;\n\nclass RealtimeStore extends AbstractRealtimeSession {\n protected state: RealtimeState = {\n status: 'disconnected',\n messages: [],\n events: [],\n isCapturing: false,\n isPlaying: false,\n };\n\n private callbacks: { [K in RealtimeStateKey]-?: Set<() => void> } = {\n status: new Set(),\n messages: new Set(),\n events: new Set(),\n isCapturing: new Set(),\n isPlaying: new Set(),\n session: new Set(),\n };\n\n get status(): RealtimeStatus {\n return this.state.status;\n }\n\n get messages(): UIMessage[] {\n return this.state.messages;\n }\n\n get events(): RealtimeServerEvent[] {\n return this.state.events;\n }\n\n get isCapturing(): boolean {\n return this.state.isCapturing;\n }\n\n get isPlaying(): boolean {\n return this.state.isPlaying;\n }\n\n get session(): RealtimeState['session'] {\n return this.state.session;\n }\n\n subscribe(key: RealtimeStateKey, onChange: () => void): () => void {\n this.callbacks[key].add(onChange);\n\n return () => {\n this.callbacks[key].delete(onChange);\n };\n }\n\n protected setState<K extends RealtimeStateKey>(\n key: K,\n value: RealtimeState[K],\n ): void {\n this.state = { ...this.state, [key]: value };\n this.callbacks[key].forEach(callback => callback());\n }\n}\n\ntype UseRealtimeReturn = {\n status: RealtimeStatus;\n messages: UIMessage[];\n events: RealtimeServerEvent[];\n isCapturing: boolean;\n isPlaying: boolean;\n session?: RealtimeState['session'];\n\n connect: RealtimeStore['connect'];\n close: RealtimeStore['close'];\n resumePlayback: () => Promise<void>;\n resumeAudioCapture: () => Promise<void>;\n disconnect: () => void;\n addToolOutput: (callId: string, result: unknown) => void;\n sendEvent: RealtimeStore['sendEvent'];\n sendTextMessage: (text: string) => void;\n sendAudio: (base64Audio: string) => void;\n commitAudio: () => void;\n clearAudioBuffer: () => void;\n requestResponse: (options?: { modalities?: string[] }) => void;\n cancelResponse: () => void;\n startAudioCapture: (stream: MediaStream) => void;\n stopAudioCapture: () => void;\n stopPlayback: () => void;\n};\n\nfunction useRealtime(options: UseRealtimeOptions): UseRealtimeReturn {\n const ownerRef = useRef<{\n store: RealtimeStore;\n onToolCall: UseRealtimeOptions['onToolCall'];\n onEvent: UseRealtimeOptions['onEvent'];\n onError: UseRealtimeOptions['onError'];\n } | null>(null);\n const {\n model,\n api,\n startupTimeoutMs,\n closeTimeoutMs,\n rtcDisconnectTimeoutMs,\n sessionConfig,\n sampleRate,\n maxEvents,\n maxPlaybackBufferSeconds,\n onToolCall,\n onEvent,\n onError,\n } = options;\n const { token, websocket, session: sessionEndpoint } = api;\n const protocols = JSON.stringify(api.protocols ?? []);\n\n // Candidates allocate no transports or media; only a committed owner can act.\n const rt = useMemo(() => {\n const store: RealtimeStore = new RealtimeStore({\n model,\n api:\n token != null\n ? { token }\n : sessionEndpoint != null\n ? { session: sessionEndpoint }\n : {\n websocket: websocket as string,\n protocols: secureJsonParse(protocols) as string[],\n },\n startupTimeoutMs,\n closeTimeoutMs,\n rtcDisconnectTimeoutMs,\n sessionConfig,\n sampleRate,\n maxEvents,\n maxPlaybackBufferSeconds,\n onEvent: (...args) =>\n ownerRef.current?.store === store\n ? ownerRef.current.onEvent?.(...args)\n : undefined,\n onError: (...args) =>\n ownerRef.current?.store === store\n ? ownerRef.current.onError?.(...args)\n : undefined,\n });\n return store;\n }, [\n model,\n token,\n sessionEndpoint,\n websocket,\n protocols,\n startupTimeoutMs,\n closeTimeoutMs,\n rtcDisconnectTimeoutMs,\n sessionConfig,\n sampleRate,\n maxEvents,\n maxPlaybackBufferSeconds,\n ]);\n\n // Publish before child layout effects; insertion cleanup only revokes refs.\n useInsertionEffect(() => {\n ownerRef.current = { store: rt, onToolCall, onEvent, onError };\n rt.onToolCall =\n onToolCall == null\n ? undefined\n : (...args) =>\n ownerRef.current?.store === rt\n ? ownerRef.current.onToolCall?.(...args)\n : undefined;\n return () => {\n ownerRef.current = null;\n };\n });\n\n // StrictMode replays layout effects, but keeps the insertion-phase owner.\n useIsomorphicLayoutEffect(() => {\n return () => rt.dispose();\n }, [rt]);\n\n const actions = useMemo(() => {\n const current = () => {\n if (ownerRef.current == null)\n throw new Error('Realtime controls require a mounted hook');\n return ownerRef.current.store;\n };\n return {\n connect: async (options?: {\n stream?: MediaStream;\n capture?: boolean;\n }) => {\n const store = current();\n return options == null ? store.connect() : store.connect(options);\n },\n close: async options => current().close(options),\n resumePlayback: async () => current().resumePlayback(),\n resumeAudioCapture: async () => current().resumeAudioCapture(),\n disconnect: () => current().disconnect(),\n addToolOutput: (callId, result) =>\n current().addToolOutput(callId, result),\n sendEvent: event => current().sendEvent(event),\n sendTextMessage: text => current().sendTextMessage(text),\n sendAudio: audio => current().sendAudio(audio),\n commitAudio: () => current().commitAudio(),\n clearAudioBuffer: () => current().clearAudioBuffer(),\n requestResponse: options => current().requestResponse(options),\n cancelResponse: () => current().cancelResponse(),\n startAudioCapture: stream => current().startAudioCapture(stream),\n stopAudioCapture: () => current().stopAudioCapture(),\n stopPlayback: () => current().stopPlayback(),\n } satisfies Omit<UseRealtimeReturn, keyof RealtimeState>;\n }, []);\n\n const status = useSyncExternalStore(\n useCallback(cb => rt.subscribe('status', cb), [rt]),\n () => rt.status,\n () => rt.status,\n );\n\n const messages = useSyncExternalStore(\n useCallback(cb => rt.subscribe('messages', cb), [rt]),\n () => rt.messages,\n () => rt.messages,\n );\n\n const events = useSyncExternalStore(\n useCallback(cb => rt.subscribe('events', cb), [rt]),\n () => rt.events,\n () => rt.events,\n );\n\n const isCapturing = useSyncExternalStore(\n useCallback(cb => rt.subscribe('isCapturing', cb), [rt]),\n () => rt.isCapturing,\n () => rt.isCapturing,\n );\n\n const isPlaying = useSyncExternalStore(\n useCallback(cb => rt.subscribe('isPlaying', cb), [rt]),\n () => rt.isPlaying,\n () => rt.isPlaying,\n );\n\n const session = useSyncExternalStore(\n useCallback(cb => rt.subscribe('session', cb), [rt]),\n () => rt.session,\n () => rt.session,\n );\n\n return {\n status,\n messages,\n events,\n isCapturing,\n isPlaying,\n session,\n ...actions,\n };\n}\n\nexport const experimental_useRealtime = useRealtime;\n\nexport type {\n RealtimeStatus as Experimental_RealtimeStatus,\n UseRealtimeOptions as Experimental_UseRealtimeOptions,\n UseRealtimeReturn as Experimental_UseRealtimeReturn,\n};\n","import type { MCPAppResource } from '@ai-sdk/mcp';\nimport { useEffect, useState } from 'react';\nimport { MCPAppFrame } from './app-frame';\nimport type { MCPAppMetadata, MCPAppRendererProps } from './types';\nimport { getMCPAppFromToolPart } from './utils';\n\ntype LoadedResourceState = {\n resourceUri: string;\n resource?: MCPAppResource;\n error?: Error;\n};\n\nfunction getToolPartOutput(part: MCPAppRendererProps['part']): unknown {\n return part.state === 'output-available' ? part.output : undefined;\n}\n\nfunction getToolPartInput(part: MCPAppRendererProps['part']): unknown {\n return part.state === 'input-available' || part.state === 'output-available'\n ? part.input\n : undefined;\n}\n\nexport function MCPAppRenderer({\n part,\n sandbox,\n resource: resourceProp,\n loadResource,\n handlers,\n hostInfo,\n hostContext,\n fallback = null,\n}: MCPAppRendererProps) {\n const app = getMCPAppFromToolPart(part);\n const [cachedApp, setCachedApp] = useState<MCPAppMetadata>();\n const [loadedResource, setLoadedResource] = useState<LoadedResourceState>();\n\n useEffect(() => {\n if (app != null) {\n setCachedApp(previous =>\n previous?.resourceUri === app.resourceUri ? previous : app,\n );\n }\n }, [app?.resourceUri]);\n\n const appForRender = app ?? cachedApp;\n\n useEffect(() => {\n if (appForRender == null || resourceProp != null || loadResource == null) {\n return;\n }\n\n let cancelled = false;\n const resourceUri = appForRender.resourceUri;\n\n loadResource(appForRender)\n .then(resource => {\n if (!cancelled) {\n setLoadedResource({ resourceUri, resource });\n }\n })\n .catch(error => {\n if (!cancelled) {\n setLoadedResource({\n resourceUri,\n error: error instanceof Error ? error : new Error(String(error)),\n });\n }\n });\n\n return () => {\n cancelled = true;\n };\n }, [appForRender?.resourceUri, loadResource, resourceProp]);\n\n const loadedResourceForApp =\n loadedResource?.resourceUri === appForRender?.resourceUri\n ? loadedResource\n : undefined;\n const resource = resourceProp ?? loadedResourceForApp?.resource;\n const error = resourceProp == null ? loadedResourceForApp?.error : undefined;\n\n if (appForRender == null || error != null || resource == null) {\n return fallback;\n }\n\n return (\n <MCPAppFrame\n app={appForRender}\n resource={resource}\n input={getToolPartInput(part)}\n output={getToolPartOutput(part)}\n sandbox={sandbox}\n handlers={handlers}\n hostInfo={hostInfo}\n hostContext={hostContext}\n />\n );\n}\n","import { useEffect, useMemo, useRef } from 'react';\nimport { MCPAppBridge } from './bridge';\nimport {\n MCP_APP_DEFAULT_INNER_SANDBOX,\n MCP_APP_DEFAULT_OUTER_SANDBOX,\n getMCPAppAllowAttribute,\n getMCPAppCSP,\n} from './sandbox';\nimport type { MCPAppFrameProps } from './types';\nimport { normalizeMCPAppToolResult } from './utils';\n\n/**\n * Derives the concrete origin of the sandbox proxy from its URL, so outbound\n * postMessage targets a specific origin instead of `'*'` and inbound messages\n * can be origin-checked. The proxy must be served from a stable, concrete\n * origin (the default outer sandbox keeps `allow-same-origin`). Falls back to\n * the host origin on a malformed URL, never `'*'`.\n */\nfunction deriveTargetOrigin(url: string): string {\n const location = typeof window !== 'undefined' ? window.location : undefined;\n try {\n return new URL(url, location?.href).origin;\n } catch {\n return location?.origin ?? 'null';\n }\n}\n\nfunction sendToolState({\n bridge,\n input,\n output,\n}: {\n bridge?: MCPAppBridge;\n input: unknown;\n output: unknown;\n}) {\n if (bridge == null) {\n return;\n }\n\n if (input !== undefined) {\n bridge.sendToolInput(input);\n }\n\n if (output !== undefined) {\n bridge.sendToolResult(normalizeMCPAppToolResult(output));\n }\n}\n\nexport function MCPAppFrame({\n app,\n resource,\n input,\n output,\n sandbox,\n handlers,\n hostInfo,\n hostContext,\n}: MCPAppFrameProps) {\n const iframeRef = useRef<HTMLIFrameElement>(null);\n const bridgeRef = useRef<MCPAppBridge | undefined>(undefined);\n const inputRef = useRef(input);\n const outputRef = useRef(output);\n const hostContextRef = useRef(hostContext);\n const initializedRef = useRef(false);\n inputRef.current = input;\n outputRef.current = output;\n hostContextRef.current = hostContext;\n const sandboxUrl = String(sandbox.url);\n const targetOrigin = sandbox.targetOrigin ?? deriveTargetOrigin(sandboxUrl);\n const resourceCSP = getMCPAppCSP(resource.meta?.csp);\n const resourceAllow = getMCPAppAllowAttribute(\n resource.meta?.permissions,\n sandbox.allowedPermissions,\n );\n const innerSandbox = sandbox.innerSandbox ?? MCP_APP_DEFAULT_INNER_SANDBOX;\n const bridgeHandlers = useMemo(\n () => ({\n ...handlers,\n onInitialized: () => {\n initializedRef.current = true;\n handlers?.onInitialized?.();\n sendToolState({\n bridge: bridgeRef.current,\n input: inputRef.current,\n output: outputRef.current,\n });\n },\n }),\n [handlers],\n );\n const bridgeHandlersRef = useRef(bridgeHandlers);\n bridgeHandlersRef.current = bridgeHandlers;\n\n useEffect(() => {\n const iframe = iframeRef.current;\n const targetWindow = iframe?.contentWindow;\n if (targetWindow == null) {\n return;\n }\n\n initializedRef.current = false;\n\n const bridge = new MCPAppBridge({\n targetWindow,\n targetOrigin,\n handlers: bridgeHandlersRef.current,\n hostInfo,\n hostContext: hostContextRef.current,\n });\n bridgeRef.current = bridge;\n\n const onMessage = (event: MessageEvent) => {\n // Only handle messages from the proxy window and expected origin.\n if (!bridge.acceptsEvent(event)) {\n return;\n }\n\n if (\n event.data?.jsonrpc === '2.0' &&\n event.data.method === 'ui/notifications/sandbox-proxy-ready'\n ) {\n bridge.sendSandboxResourceReady({\n html: resource.html,\n csp: resourceCSP,\n sandbox: innerSandbox,\n allow: resourceAllow,\n });\n return;\n }\n\n bridge.handleMessage(event);\n };\n\n window.addEventListener('message', onMessage);\n\n return () => {\n initializedRef.current = false;\n window.removeEventListener('message', onMessage);\n void bridge.teardownResource().catch(() => {});\n bridge.close();\n bridgeRef.current = undefined;\n };\n }, [\n hostInfo,\n innerSandbox,\n resource.html,\n resourceAllow,\n resourceCSP,\n sandboxUrl,\n targetOrigin,\n ]);\n\n useEffect(() => {\n bridgeRef.current?.setHandlers(bridgeHandlers);\n }, [bridgeHandlers]);\n\n useEffect(() => {\n if (hostContext != null) {\n bridgeRef.current?.setHostContext(hostContext);\n }\n }, [hostContext]);\n\n useEffect(() => {\n if (initializedRef.current && input !== undefined) {\n bridgeRef.current?.sendToolInput(input);\n }\n }, [input]);\n\n useEffect(() => {\n if (initializedRef.current && output !== undefined) {\n bridgeRef.current?.sendToolResult(normalizeMCPAppToolResult(output));\n }\n }, [output]);\n\n return (\n <iframe\n ref={iframeRef}\n title=\"MCP App\"\n aria-label={sandbox.title ?? app.resourceUri}\n src={sandboxUrl}\n className={sandbox.className}\n style={sandbox.style}\n // Permissions Policy is hierarchical: the outer frame must delegate a\n // feature for the proxy to re-delegate it to the inner app frame.\n allow={resourceAllow}\n sandbox={sandbox.outerSandbox ?? MCP_APP_DEFAULT_OUTER_SANDBOX}\n />\n );\n}\n","import { isJSONObject } from '@ai-sdk/provider';\nimport type {\n MCPAppBridgeHandlers,\n MCPAppHostContext,\n MCPAppJsonRpcMessage,\n MCPAppJsonRpcNotification,\n MCPAppJsonRpcRequest,\n MCPAppJsonRpcResponse,\n MCPAppToolCallParams,\n} from './types';\n\nconst MCP_APP_PROTOCOL_VERSION = '2026-01-26';\n\n/**\n * Checks whether an iframe message looks like a JSON-RPC 2.0 message.\n */\nfunction isJsonRpcMessage(value: unknown): value is MCPAppJsonRpcMessage {\n return (\n value != null &&\n typeof value === 'object' &&\n !Array.isArray(value) &&\n 'jsonrpc' in value &&\n value.jsonrpc === '2.0'\n );\n}\n\n/**\n * Checks whether a JSON-RPC message expects a response.\n */\nfunction isRequest(\n message: MCPAppJsonRpcMessage,\n): message is MCPAppJsonRpcRequest {\n return 'method' in message && 'id' in message;\n}\n\n/**\n * Checks whether a JSON-RPC message is a fire-and-forget notification.\n */\nfunction isNotification(\n message: MCPAppJsonRpcMessage,\n): message is MCPAppJsonRpcNotification {\n return 'method' in message && !('id' in message);\n}\n\n/**\n * Normalizes unknown thrown values into an `Error`.\n */\nfunction toError(error: unknown): Error {\n return error instanceof Error ? error : new Error(String(error));\n}\n\n/**\n * Validates the params for app-initiated `tools/call` requests.\n */\nfunction assertToolCallParams(params: unknown): MCPAppToolCallParams {\n if (!isJSONObject(params) || typeof params.name !== 'string') {\n throw new Error('Invalid tools/call params');\n }\n\n return {\n name: params.name,\n arguments: isJSONObject(params.arguments) ? params.arguments : undefined,\n };\n}\n\n/**\n * Validates `resources/read` params and limits reads to `ui://` app resources.\n */\nfunction assertResourceReadParams(params: unknown): { uri: string } {\n if (!isJSONObject(params) || typeof params.uri !== 'string') {\n throw new Error('Invalid resources/read params');\n }\n if (!params.uri.startsWith('ui://')) {\n throw new Error(\n `resources/read is limited to ui:// resources: ${params.uri}`,\n );\n }\n return { uri: params.uri };\n}\n\n/**\n * Validates `ui/open-link` params and allows only `https:`/`http:`/`mailto:`\n * URLs.\n */\nfunction assertOpenLinkParams(params: unknown): { url: string } {\n if (!isJSONObject(params) || typeof params.url !== 'string') {\n throw new Error('Invalid ui/open-link params');\n }\n\n let scheme: string;\n try {\n scheme = new URL(params.url).protocol;\n } catch {\n throw new Error(`Invalid ui/open-link url: ${params.url}`);\n }\n\n if (scheme !== 'https:' && scheme !== 'http:' && scheme !== 'mailto:') {\n throw new Error(`Disallowed ui/open-link scheme: ${scheme}`);\n }\n\n return { url: params.url };\n}\n\n/**\n * Validates params for `ui/request-display-mode`.\n */\nfunction assertDisplayModeParams(params: unknown): {\n mode: 'inline' | 'fullscreen' | 'pip';\n} {\n if (\n !isJSONObject(params) ||\n (params.mode !== 'inline' &&\n params.mode !== 'fullscreen' &&\n params.mode !== 'pip')\n ) {\n throw new Error('Invalid ui/request-display-mode params');\n }\n return { mode: params.mode };\n}\n\n/**\n * Host-side JSON-RPC bridge for one MCP App iframe.\n *\n * It handles the MCP Apps initialization handshake, sends tool input/result\n * notifications to the iframe, and proxies allowed iframe requests through\n * host-provided callbacks.\n *\n * @example\n * ```ts\n * const bridge = new MCPAppBridge({\n * targetWindow: iframe.contentWindow!,\n * handlers: {\n * allowedTools: ['refreshDashboardData'],\n * callTool: params => client.callTool(params),\n * },\n * });\n *\n * window.addEventListener('message', event => bridge.handleMessage(event));\n * bridge.sendToolInput({ topic: 'usage' });\n * ```\n */\nexport class MCPAppBridge {\n private initialized = false;\n private pendingNotifications: MCPAppJsonRpcNotification[] = [];\n private nextRequestId = 0;\n private pendingResponses = new Map<\n string | number,\n {\n resolve: (value: unknown) => void;\n reject: (error: Error) => void;\n }\n >();\n\n constructor({\n targetWindow,\n targetOrigin = '*',\n handlers = {},\n hostInfo = { name: 'ai-sdk-react', version: '1.0.0' },\n hostContext = { displayMode: 'inline' },\n }: {\n targetWindow: Window;\n targetOrigin?: string;\n handlers?: MCPAppBridgeHandlers;\n hostInfo?: { name: string; version: string };\n hostContext?: MCPAppHostContext;\n }) {\n this.targetWindow = targetWindow;\n this.targetOrigin = targetOrigin;\n this.handlers = handlers;\n this.hostInfo = hostInfo;\n this.hostContext = hostContext;\n }\n\n private targetWindow: Window;\n private targetOrigin: string;\n private handlers: MCPAppBridgeHandlers;\n private hostInfo: { name: string; version: string };\n private hostContext: MCPAppHostContext;\n\n /**\n * Replaces the callbacks used to serve iframe requests.\n */\n setHandlers(handlers: MCPAppBridgeHandlers): void {\n this.handlers = handlers;\n }\n\n /**\n * Updates host context and notifies the iframe after initialization.\n *\n * @example\n * ```ts\n * bridge.setHostContext({ theme: 'dark', displayMode: 'inline' });\n * ```\n */\n setHostContext(hostContext: MCPAppHostContext): void {\n this.hostContext = hostContext;\n this.sendNotification({\n method: 'ui/notifications/host-context-changed',\n params: hostContext,\n });\n }\n\n /**\n * Whether a `message` event came from the expected proxy window and origin.\n * The origin check is skipped only when `targetOrigin` is the `'*'` default.\n * Callers that intercept events before {@link handleMessage} share this check.\n */\n acceptsEvent(event: MessageEvent): boolean {\n return (\n event.source === this.targetWindow &&\n (this.targetOrigin === '*' || event.origin === this.targetOrigin)\n );\n }\n\n /**\n * Processes one `message` event from the sandbox proxy iframe.\n */\n handleMessage(event: MessageEvent): void {\n if (!this.acceptsEvent(event) || !isJsonRpcMessage(event.data)) {\n return;\n }\n\n const message = event.data;\n\n if ('result' in message || 'error' in message) {\n this.handleResponse(message);\n return;\n }\n\n if (isRequest(message)) {\n void this.handleRequest(message);\n return;\n }\n\n if (isNotification(message)) {\n this.handleNotification(message);\n }\n }\n\n /**\n * Sends app HTML and sandbox settings to the sandbox proxy.\n */\n sendSandboxResourceReady(params: unknown): void {\n this.post({\n jsonrpc: '2.0',\n method: 'ui/notifications/sandbox-resource-ready',\n params,\n });\n }\n\n /**\n * Sends final tool arguments to the MCP App.\n */\n sendToolInput(input: unknown): void {\n this.sendNotification({\n method: 'ui/notifications/tool-input',\n params: { arguments: input },\n });\n }\n\n /**\n * Sends a completed MCP tool result to the MCP App.\n */\n sendToolResult(result: unknown): void {\n this.sendNotification({\n method: 'ui/notifications/tool-result',\n params: result,\n });\n }\n\n /**\n * Notifies the MCP App that the related tool call was cancelled.\n */\n sendToolCancelled(reason?: string): void {\n this.sendNotification({\n method: 'ui/notifications/tool-cancelled',\n params: reason != null ? { reason } : {},\n });\n }\n\n /**\n * Requests graceful teardown before the host removes the iframe.\n */\n teardownResource(): Promise<unknown> {\n return this.request('ui/resource-teardown', {});\n }\n\n /**\n * Rejects pending bridge requests and clears queued notifications.\n */\n close(): void {\n for (const pending of this.pendingResponses.values()) {\n pending.reject(new Error('MCP App bridge closed'));\n }\n this.pendingResponses.clear();\n this.pendingNotifications = [];\n }\n\n /**\n * Resolves or rejects a host-initiated request when the iframe responds.\n */\n private handleResponse(response: MCPAppJsonRpcResponse): void {\n const pending = this.pendingResponses.get(response.id);\n if (pending == null) {\n return;\n }\n\n this.pendingResponses.delete(response.id);\n\n if (response.error != null) {\n pending.reject(new Error(response.error.message));\n } else {\n pending.resolve(response.result);\n }\n }\n\n /**\n * Runs a handler for an iframe request and posts the JSON-RPC response.\n */\n private async handleRequest(request: MCPAppJsonRpcRequest): Promise<void> {\n try {\n const result = await this.getRequestResult(request);\n this.post({ jsonrpc: '2.0', id: request.id, result });\n } catch (error) {\n const normalizedError = toError(error);\n this.handlers.onError?.(normalizedError);\n this.post({\n jsonrpc: '2.0',\n id: request.id,\n error: { code: -32603, message: normalizedError.message },\n });\n }\n }\n\n /**\n * Maps supported iframe request methods to host callbacks.\n */\n private async getRequestResult(\n request: MCPAppJsonRpcRequest,\n ): Promise<unknown> {\n switch (request.method) {\n case 'ui/initialize':\n return {\n protocolVersion: MCP_APP_PROTOCOL_VERSION,\n hostCapabilities: {\n ...(this.handlers.callTool != null ? { serverTools: {} } : {}),\n ...(this.handlers.readResource != null\n ? { serverResources: {} }\n : {}),\n ...(this.handlers.onLog != null ? { logging: {} } : {}),\n },\n hostInfo: this.hostInfo,\n hostContext: this.hostContext,\n };\n\n case 'tools/call': {\n if (this.handlers.callTool == null) {\n throw new Error('No tools/call handler configured');\n }\n const params = assertToolCallParams(request.params);\n // Deny-by-default: the (untrusted) MCP App may only invoke tools the\n // host has explicitly allow-listed. Omitting `allowedTools` exposes no\n // tools, rather than forwarding every requested tool to `callTool`.\n if (\n this.handlers.allowedTools == null ||\n !this.handlers.allowedTools.includes(params.name)\n ) {\n throw new Error(`Tool is not app-visible: ${params.name}`);\n }\n return this.handlers.callTool(params);\n }\n\n case 'resources/read':\n if (this.handlers.readResource == null) {\n throw new Error('No resources/read handler configured');\n }\n return this.handlers.readResource(\n assertResourceReadParams(request.params),\n );\n\n case 'resources/list':\n if (this.handlers.listResources == null) {\n throw new Error('No resources/list handler configured');\n }\n return this.handlers.listResources(request.params);\n\n case 'ui/open-link':\n if (this.handlers.openLink == null) {\n throw new Error('No ui/open-link handler configured');\n }\n return this.handlers.openLink(assertOpenLinkParams(request.params));\n\n case 'ui/message':\n return this.handlers.sendMessage?.(request.params) ?? {};\n\n case 'ui/update-model-context':\n return this.handlers.updateModelContext?.(request.params) ?? {};\n\n case 'ui/request-display-mode':\n return (\n this.handlers.requestDisplayMode?.(\n assertDisplayModeParams(request.params),\n ) ?? { mode: this.hostContext.displayMode ?? 'inline' }\n );\n\n default:\n throw new Error(`Unsupported MCP App method: ${request.method}`);\n }\n }\n\n /**\n * Handles iframe lifecycle and telemetry notifications.\n */\n private handleNotification(notification: MCPAppJsonRpcNotification): void {\n switch (notification.method) {\n case 'ui/notifications/initialized':\n this.initialized = true;\n this.flushNotifications();\n this.handlers.onInitialized?.();\n break;\n case 'ui/notifications/size-changed':\n this.handlers.onSizeChange?.(\n notification.params as { width?: number; height?: number },\n );\n break;\n case 'ui/notifications/request-teardown':\n this.handlers.onRequestTeardown?.(notification.params);\n break;\n case 'notifications/message':\n this.handlers.onLog?.(notification.params);\n break;\n }\n }\n\n /**\n * Sends a host-to-iframe notification, queueing it until app initialization.\n */\n private sendNotification(\n notification: Omit<MCPAppJsonRpcNotification, 'jsonrpc'>,\n ) {\n const message = { jsonrpc: '2.0' as const, ...notification };\n if (!this.initialized && !notification.method.includes('sandbox')) {\n this.pendingNotifications.push(message);\n return;\n }\n this.post(message);\n }\n\n /**\n * Sends notifications that were queued before `ui/notifications/initialized`.\n */\n private flushNotifications(): void {\n const notifications = this.pendingNotifications;\n this.pendingNotifications = [];\n for (const notification of notifications) {\n this.post(notification);\n }\n }\n\n /**\n * Sends a host-initiated JSON-RPC request to the iframe.\n */\n private request(method: string, params: unknown): Promise<unknown> {\n const id = this.nextRequestId++;\n this.post({ jsonrpc: '2.0', id, method, params });\n return new Promise((resolve, reject) => {\n this.pendingResponses.set(id, { resolve, reject });\n });\n }\n\n /**\n * Posts a JSON-RPC message to the sandbox proxy iframe.\n */\n private post(message: MCPAppJsonRpcMessage): void {\n this.targetWindow.postMessage(message, this.targetOrigin);\n }\n}\n","import type { MCPAppResourceCSP } from '@ai-sdk/mcp';\n\n// CSP source values come from the (untrusted) MCP server. Rather than\n// denylisting bad characters on the raw string (which an encoding like \"%3B\"\n// can slip past), canonicalize each value: parse it as an absolute URL so any\n// percent-encoding is decoded, keep only https/wss origins, then re-check the\n// decoded origin so a separator that decoded back into \";\" \",\" or whitespace\n// cannot split the directive.\nconst ALLOWED_CSP_SCHEMES = new Set(['https:', 'wss:']);\n\nfunction sanitizeCSPSources(sources?: string[]): string[] {\n const result: string[] = [];\n for (const source of sources ?? []) {\n if (typeof source !== 'string') {\n continue;\n }\n\n let origin: string;\n try {\n const url = new URL(source);\n // Reject non-https/wss, the empty host, and a bare \"*\" host (which would\n // match every origin and defeat the allowlist, like scheme-only \"https:\").\n if (\n !ALLOWED_CSP_SCHEMES.has(url.protocol) ||\n url.host.length === 0 ||\n url.host === '*'\n ) {\n continue;\n }\n origin = url.origin;\n } catch {\n continue;\n }\n\n // Drop separators that split the directive and quotes that could break out\n // of an HTML attribute the policy may be embedded in downstream.\n if (/[\"'`\\s;,]/.test(origin)) {\n continue;\n }\n\n result.push(origin);\n }\n return result;\n}\n\n/**\n * Default sandbox permissions for the outer sandbox proxy iframe.\n */\nexport const MCP_APP_DEFAULT_OUTER_SANDBOX =\n 'allow-scripts allow-same-origin allow-forms';\n\n/**\n * Default sandbox permissions for the inner iframe that runs app HTML.\n */\nexport const MCP_APP_DEFAULT_INNER_SANDBOX = 'allow-scripts allow-forms';\n\n/**\n * Converts MCP App CSP metadata into a Content-Security-Policy string.\n *\n * The returned value is meant to be passed to a sandbox proxy, which can apply\n * it to the inner iframe document.\n *\n * @example\n * ```ts\n * const csp = getMCPAppCSP({\n * connectDomains: ['https://api.example.com'],\n * resourceDomains: ['https://cdn.example.com'],\n * });\n * ```\n */\nexport function getMCPAppCSP(csp?: MCPAppResourceCSP): string | undefined {\n if (csp == null) {\n return undefined;\n }\n\n const connectSrc = [\"'self'\", ...sanitizeCSPSources(csp.connectDomains)];\n const imgSrc = [\n \"'self'\",\n 'data:',\n ...sanitizeCSPSources(csp.resourceDomains),\n ];\n const frameSrc = [\"'self'\", ...sanitizeCSPSources(csp.frameDomains)];\n\n return [\n \"default-src 'none'\",\n \"base-uri 'none'\",\n \"form-action 'none'\",\n \"script-src 'unsafe-inline'\",\n \"style-src 'unsafe-inline'\",\n `connect-src ${connectSrc.join(' ')}`,\n `img-src ${imgSrc.join(' ')}`,\n `font-src ${imgSrc.join(' ')}`,\n `frame-src ${frameSrc.join(' ')}`,\n ].join('; ');\n}\n\n/**\n * A permission an MCP App may request and a host may allow.\n */\nexport type MCPAppPermission =\n | 'camera'\n | 'microphone'\n | 'geolocation'\n | 'clipboardWrite';\n\nconst MCP_APP_PERMISSION_FEATURES: Record<MCPAppPermission, string> = {\n camera: 'camera',\n microphone: 'microphone',\n geolocation: 'geolocation',\n clipboardWrite: 'clipboard-write',\n};\n\n/**\n * Converts MCP App permission metadata into an iframe `allow` attribute.\n *\n * Deny-by-default: a capability is granted only when it is both requested in\n * `permissions` and present in the host `allowedPermissions` allowlist.\n * Omitting the allowlist grants nothing, mirroring `allowedTools` in the bridge.\n *\n * @example\n * ```ts\n * const allow = getMCPAppAllowAttribute(\n * { microphone: {}, camera: {} },\n * ['microphone'],\n * );\n * // \"microphone\" — camera requested by server but not host-allowed\n * ```\n */\nexport function getMCPAppAllowAttribute(\n permissions?: Record<string, unknown>,\n allowedPermissions?: MCPAppPermission[],\n): string | undefined {\n if (permissions == null || allowedPermissions == null) {\n return undefined;\n }\n\n const allow = allowedPermissions\n .filter(permission => Boolean(permissions[permission]))\n .map(permission => MCP_APP_PERMISSION_FEATURES[permission]);\n\n return allow.length > 0 ? allow.join('; ') : undefined;\n}\n","import { isJSONObject } from '@ai-sdk/provider';\nimport type { MCPAppMetadata, MCPAppRendererProps } from './types';\n\n/**\n * Extracts MCP App metadata from an AI SDK tool UI part.\n *\n * @example\n * ```ts\n * const app = getMCPAppFromToolPart({\n * type: 'dynamic-tool',\n * toolName: 'showDashboard',\n * toolCallId: 'call-1',\n * state: 'input-available',\n * input: { topic: 'usage' },\n * toolMetadata: {\n * app: {\n * resourceUri: 'ui://example/dashboard',\n * mimeType: 'text/html;profile=mcp-app',\n * },\n * },\n * });\n * // { resourceUri: 'ui://example/dashboard', mimeType: 'text/html;profile=mcp-app' }\n * ```\n */\nexport function getMCPAppFromToolPart(\n part: MCPAppRendererProps['part'],\n): MCPAppMetadata | undefined {\n const rawAppMetadata = part.toolMetadata?.app;\n const appMetadata = isJSONObject(rawAppMetadata) ? rawAppMetadata : undefined;\n\n if (\n appMetadata == null ||\n appMetadata.mimeType !== 'text/html;profile=mcp-app' ||\n typeof appMetadata.resourceUri !== 'string' ||\n !appMetadata.resourceUri.startsWith('ui://') ||\n (appMetadata.visibility != null &&\n (!Array.isArray(appMetadata.visibility) ||\n appMetadata.visibility.some(\n value => value !== 'model' && value !== 'app',\n )))\n ) {\n return undefined;\n }\n\n return appMetadata as MCPAppMetadata;\n}\n\n/**\n * Converts an AI SDK tool output into the MCP Apps tool-result shape.\n *\n * MCP Apps expect tool results to have `content` and optional\n * `structuredContent`. MCP tools already return that shape, but typed AI SDK\n * tools may return only structured data. This helper wraps structured-only\n * outputs so the iframe can receive a valid tool result notification.\n *\n * @example\n * ```ts\n * normalizeMCPAppToolResult({ cards: [] });\n * // { content: [], structuredContent: { cards: [] } }\n * ```\n */\nexport function normalizeMCPAppToolResult(output: unknown): {\n content: unknown[];\n structuredContent?: unknown;\n isError?: boolean;\n} {\n if (output != null && typeof output === 'object' && 'content' in output) {\n return output as {\n content: unknown[];\n structuredContent?: unknown;\n isError?: boolean;\n };\n }\n\n return {\n content: [],\n structuredContent: output,\n };\n}\n","import type { FlexibleSchema } from '@ai-sdk/provider-utils';\nimport {\n useObject,\n type UseObjectHelpers,\n type UseObjectOptions,\n} from './use-object';\n\nexport * from './use-chat';\nexport { Chat } from './chat.react';\nexport * from './use-completion';\nexport * from './use-object';\nexport * from './use-realtime';\nexport * from './mcp-apps';\n\n// deprecated aliases\n// note: declared here (instead of export aliases) so that the `@deprecated`\n// tags are preserved in the bundled type declarations\n\n/**\n * @deprecated Use `useObject` instead.\n */\nexport const experimental_useObject = useObject;\n\n/**\n * @deprecated Use `UseObjectOptions` instead.\n */\nexport type Experimental_UseObjectOptions<\n SCHEMA extends FlexibleSchema,\n RESULT,\n> = UseObjectOptions<SCHEMA, RESULT>;\n\n/**\n * @deprecated Use `UseObjectHelpers` instead.\n */\nexport type Experimental_UseObjectHelpers<RESULT, INPUT> = UseObjectHelpers<\n RESULT,\n INPUT\n>;\n"],"mappings":"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","names":["fetch","error","useCallback","useRef","throttle","useRef","useCallback","useCallback","useEffect","useId","useRef","useState","useSWR","fetch","useId","useSWR","useState","useRef","useEffect","useCallback","completion","useCallback","useEffect","useMemo","useRef","useSyncExternalStore","_a","options","useEffect","useState","useEffect","useMemo","useRef","resolve","isJSONObject","useRef","useMemo","_a","useEffect","jsx","useState","useEffect","resource","error"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-sdk/react",
3
- "version": "4.0.104",
3
+ "version": "4.0.106",
4
4
  "type": "module",
5
5
  "license": "Apache-2.0",
6
6
  "sideEffects": false,
@@ -26,10 +26,10 @@
26
26
  "README.md"
27
27
  ],
28
28
  "dependencies": {
29
- "@ai-sdk/mcp": "2.0.49",
30
- "@ai-sdk/provider": "4.0.14",
31
- "@ai-sdk/provider-utils": "5.0.40",
32
- "ai": "7.0.101",
29
+ "@ai-sdk/mcp": "2.0.51",
30
+ "@ai-sdk/provider": "4.0.16",
31
+ "@ai-sdk/provider-utils": "5.0.42",
32
+ "ai": "7.0.103",
33
33
  "swr": "^2.4.1",
34
34
  "throttleit": "2.1.0"
35
35
  },
@@ -1,3 +1,4 @@
1
+ import { secureJsonParse } from '@ai-sdk/provider-utils';
1
2
  import {
2
3
  Experimental_AbstractRealtimeSession as AbstractRealtimeSession,
3
4
  type Experimental_RealtimeServerEvent as RealtimeServerEvent,
@@ -6,41 +7,22 @@ import {
6
7
  type Experimental_RealtimeStatus as RealtimeStatus,
7
8
  type UIMessage,
8
9
  } from 'ai';
9
- import { useCallback, useEffect, useRef, useSyncExternalStore } from 'react';
10
+ import {
11
+ useCallback,
12
+ useEffect,
13
+ useInsertionEffect,
14
+ useLayoutEffect,
15
+ useMemo,
16
+ useRef,
17
+ useSyncExternalStore,
18
+ } from 'react';
10
19
 
11
20
  type UseRealtimeOptions = RealtimeSessionOptions;
12
21
 
13
22
  type RealtimeStateKey = keyof RealtimeState;
14
- type RealtimeStoreKey = {
15
- model: RealtimeSessionOptions['model'];
16
- token: RealtimeSessionOptions['api']['token'];
17
- sessionConfig: RealtimeSessionOptions['sessionConfig'];
18
- sampleRate: RealtimeSessionOptions['sampleRate'];
19
- maxEvents: RealtimeSessionOptions['maxEvents'];
20
- };
21
23
 
22
- function getRealtimeStoreKey(options: UseRealtimeOptions): RealtimeStoreKey {
23
- return {
24
- model: options.model,
25
- token: options.api.token,
26
- sessionConfig: options.sessionConfig,
27
- sampleRate: options.sampleRate,
28
- maxEvents: options.maxEvents,
29
- };
30
- }
31
-
32
- function shouldCreateRealtimeStore(
33
- currentKey: RealtimeStoreKey,
34
- nextOptions: UseRealtimeOptions,
35
- ): boolean {
36
- return (
37
- currentKey.model !== nextOptions.model ||
38
- currentKey.token !== nextOptions.api.token ||
39
- currentKey.sessionConfig !== nextOptions.sessionConfig ||
40
- currentKey.sampleRate !== nextOptions.sampleRate ||
41
- currentKey.maxEvents !== nextOptions.maxEvents
42
- );
43
- }
24
+ const useIsomorphicLayoutEffect =
25
+ typeof window === 'undefined' ? useEffect : useLayoutEffect;
44
26
 
45
27
  class RealtimeStore extends AbstractRealtimeSession {
46
28
  protected state: RealtimeState = {
@@ -51,12 +33,13 @@ class RealtimeStore extends AbstractRealtimeSession {
51
33
  isPlaying: false,
52
34
  };
53
35
 
54
- private callbacks: { [K in RealtimeStateKey]: Set<() => void> } = {
36
+ private callbacks: { [K in RealtimeStateKey]-?: Set<() => void> } = {
55
37
  status: new Set(),
56
38
  messages: new Set(),
57
39
  events: new Set(),
58
40
  isCapturing: new Set(),
59
41
  isPlaying: new Set(),
42
+ session: new Set(),
60
43
  };
61
44
 
62
45
  get status(): RealtimeStatus {
@@ -79,6 +62,10 @@ class RealtimeStore extends AbstractRealtimeSession {
79
62
  return this.state.isPlaying;
80
63
  }
81
64
 
65
+ get session(): RealtimeState['session'] {
66
+ return this.state.session;
67
+ }
68
+
82
69
  subscribe(key: RealtimeStateKey, onChange: () => void): () => void {
83
70
  this.callbacks[key].add(onChange);
84
71
 
@@ -94,36 +81,6 @@ class RealtimeStore extends AbstractRealtimeSession {
94
81
  this.state = { ...this.state, [key]: value };
95
82
  this.callbacks[key].forEach(callback => callback());
96
83
  }
97
-
98
- protected pushMessage(message: UIMessage): void {
99
- this.state = {
100
- ...this.state,
101
- messages: [...this.state.messages, message],
102
- };
103
- this.callbacks.messages.forEach(callback => callback());
104
- }
105
-
106
- protected updateMessages(
107
- updater: (messages: UIMessage[]) => UIMessage[],
108
- ): void {
109
- this.state = {
110
- ...this.state,
111
- messages: updater(this.state.messages),
112
- };
113
- this.callbacks.messages.forEach(callback => callback());
114
- }
115
-
116
- protected pushEvent(event: RealtimeServerEvent): void {
117
- const nextEvents = [...this.state.events, event];
118
- this.state = {
119
- ...this.state,
120
- events:
121
- nextEvents.length > this.maxEvents
122
- ? nextEvents.slice(-this.maxEvents)
123
- : nextEvents,
124
- };
125
- this.callbacks.events.forEach(callback => callback());
126
- }
127
84
  }
128
85
 
129
86
  type UseRealtimeReturn = {
@@ -132,8 +89,12 @@ type UseRealtimeReturn = {
132
89
  events: RealtimeServerEvent[];
133
90
  isCapturing: boolean;
134
91
  isPlaying: boolean;
92
+ session?: RealtimeState['session'];
135
93
 
136
- connect: () => Promise<void>;
94
+ connect: RealtimeStore['connect'];
95
+ close: RealtimeStore['close'];
96
+ resumePlayback: () => Promise<void>;
97
+ resumeAudioCapture: () => Promise<void>;
137
98
  disconnect: () => void;
138
99
  addToolOutput: (callId: string, result: unknown) => void;
139
100
  sendEvent: RealtimeStore['sendEvent'];
@@ -149,43 +110,126 @@ type UseRealtimeReturn = {
149
110
  };
150
111
 
151
112
  function useRealtime(options: UseRealtimeOptions): UseRealtimeReturn {
152
- const callbacksRef = useRef({
153
- onToolCall: options.onToolCall,
154
- onEvent: options.onEvent,
155
- onError: options.onError,
156
- });
157
- callbacksRef.current = {
158
- onToolCall: options.onToolCall,
159
- onEvent: options.onEvent,
160
- onError: options.onError,
161
- };
162
-
163
- const realtimeRef = useRef<{
113
+ const ownerRef = useRef<{
164
114
  store: RealtimeStore;
165
- key: RealtimeStoreKey;
115
+ onToolCall: UseRealtimeOptions['onToolCall'];
116
+ onEvent: UseRealtimeOptions['onEvent'];
117
+ onError: UseRealtimeOptions['onError'];
166
118
  } | null>(null);
167
-
168
- let realtimeEntry = realtimeRef.current;
169
-
170
- if (
171
- realtimeEntry == null ||
172
- shouldCreateRealtimeStore(realtimeEntry.key, options)
173
- ) {
174
- realtimeEntry = {
175
- store: new RealtimeStore({
176
- ...options,
177
- onToolCall: (...args) => callbacksRef.current.onToolCall?.(...args),
178
- onEvent: (...args) => callbacksRef.current.onEvent?.(...args),
179
- onError: (...args) => callbacksRef.current.onError?.(...args),
180
- }),
181
- key: getRealtimeStoreKey(options),
119
+ const {
120
+ model,
121
+ api,
122
+ startupTimeoutMs,
123
+ closeTimeoutMs,
124
+ rtcDisconnectTimeoutMs,
125
+ sessionConfig,
126
+ sampleRate,
127
+ maxEvents,
128
+ maxPlaybackBufferSeconds,
129
+ onToolCall,
130
+ onEvent,
131
+ onError,
132
+ } = options;
133
+ const { token, websocket, session: sessionEndpoint } = api;
134
+ const protocols = JSON.stringify(api.protocols ?? []);
135
+
136
+ // Candidates allocate no transports or media; only a committed owner can act.
137
+ const rt = useMemo(() => {
138
+ const store: RealtimeStore = new RealtimeStore({
139
+ model,
140
+ api:
141
+ token != null
142
+ ? { token }
143
+ : sessionEndpoint != null
144
+ ? { session: sessionEndpoint }
145
+ : {
146
+ websocket: websocket as string,
147
+ protocols: secureJsonParse(protocols) as string[],
148
+ },
149
+ startupTimeoutMs,
150
+ closeTimeoutMs,
151
+ rtcDisconnectTimeoutMs,
152
+ sessionConfig,
153
+ sampleRate,
154
+ maxEvents,
155
+ maxPlaybackBufferSeconds,
156
+ onEvent: (...args) =>
157
+ ownerRef.current?.store === store
158
+ ? ownerRef.current.onEvent?.(...args)
159
+ : undefined,
160
+ onError: (...args) =>
161
+ ownerRef.current?.store === store
162
+ ? ownerRef.current.onError?.(...args)
163
+ : undefined,
164
+ });
165
+ return store;
166
+ }, [
167
+ model,
168
+ token,
169
+ sessionEndpoint,
170
+ websocket,
171
+ protocols,
172
+ startupTimeoutMs,
173
+ closeTimeoutMs,
174
+ rtcDisconnectTimeoutMs,
175
+ sessionConfig,
176
+ sampleRate,
177
+ maxEvents,
178
+ maxPlaybackBufferSeconds,
179
+ ]);
180
+
181
+ // Publish before child layout effects; insertion cleanup only revokes refs.
182
+ useInsertionEffect(() => {
183
+ ownerRef.current = { store: rt, onToolCall, onEvent, onError };
184
+ rt.onToolCall =
185
+ onToolCall == null
186
+ ? undefined
187
+ : (...args) =>
188
+ ownerRef.current?.store === rt
189
+ ? ownerRef.current.onToolCall?.(...args)
190
+ : undefined;
191
+ return () => {
192
+ ownerRef.current = null;
182
193
  };
183
- realtimeRef.current = realtimeEntry;
184
- } else {
185
- realtimeEntry.key = getRealtimeStoreKey(options);
186
- }
194
+ });
195
+
196
+ // StrictMode replays layout effects, but keeps the insertion-phase owner.
197
+ useIsomorphicLayoutEffect(() => {
198
+ return () => rt.dispose();
199
+ }, [rt]);
187
200
 
188
- const rt = realtimeEntry.store;
201
+ const actions = useMemo(() => {
202
+ const current = () => {
203
+ if (ownerRef.current == null)
204
+ throw new Error('Realtime controls require a mounted hook');
205
+ return ownerRef.current.store;
206
+ };
207
+ return {
208
+ connect: async (options?: {
209
+ stream?: MediaStream;
210
+ capture?: boolean;
211
+ }) => {
212
+ const store = current();
213
+ return options == null ? store.connect() : store.connect(options);
214
+ },
215
+ close: async options => current().close(options),
216
+ resumePlayback: async () => current().resumePlayback(),
217
+ resumeAudioCapture: async () => current().resumeAudioCapture(),
218
+ disconnect: () => current().disconnect(),
219
+ addToolOutput: (callId, result) =>
220
+ current().addToolOutput(callId, result),
221
+ sendEvent: event => current().sendEvent(event),
222
+ sendTextMessage: text => current().sendTextMessage(text),
223
+ sendAudio: audio => current().sendAudio(audio),
224
+ commitAudio: () => current().commitAudio(),
225
+ clearAudioBuffer: () => current().clearAudioBuffer(),
226
+ requestResponse: options => current().requestResponse(options),
227
+ cancelResponse: () => current().cancelResponse(),
228
+ startAudioCapture: stream => current().startAudioCapture(stream),
229
+ stopAudioCapture: () => current().stopAudioCapture(),
230
+ stopPlayback: () => current().stopPlayback(),
231
+ } satisfies Omit<UseRealtimeReturn, keyof RealtimeState>;
232
+ }, []);
189
233
 
190
234
  const status = useSyncExternalStore(
191
235
  useCallback(cb => rt.subscribe('status', cb), [rt]),
@@ -217,9 +261,11 @@ function useRealtime(options: UseRealtimeOptions): UseRealtimeReturn {
217
261
  () => rt.isPlaying,
218
262
  );
219
263
 
220
- useEffect(() => {
221
- return () => rt.dispose();
222
- }, [rt]);
264
+ const session = useSyncExternalStore(
265
+ useCallback(cb => rt.subscribe('session', cb), [rt]),
266
+ () => rt.session,
267
+ () => rt.session,
268
+ );
223
269
 
224
270
  return {
225
271
  status,
@@ -227,19 +273,8 @@ function useRealtime(options: UseRealtimeOptions): UseRealtimeReturn {
227
273
  events,
228
274
  isCapturing,
229
275
  isPlaying,
230
- connect: rt.connect.bind(rt),
231
- disconnect: rt.disconnect.bind(rt),
232
- addToolOutput: rt.addToolOutput.bind(rt),
233
- sendEvent: rt.sendEvent.bind(rt),
234
- sendTextMessage: rt.sendTextMessage.bind(rt),
235
- sendAudio: rt.sendAudio.bind(rt),
236
- commitAudio: rt.commitAudio.bind(rt),
237
- clearAudioBuffer: rt.clearAudioBuffer.bind(rt),
238
- requestResponse: rt.requestResponse.bind(rt),
239
- cancelResponse: rt.cancelResponse.bind(rt),
240
- startAudioCapture: rt.startAudioCapture.bind(rt),
241
- stopAudioCapture: rt.stopAudioCapture.bind(rt),
242
- stopPlayback: rt.stopPlayback.bind(rt),
276
+ session,
277
+ ...actions,
243
278
  };
244
279
  }
245
280