@ably/ai-transport 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (163) hide show
  1. package/README.md +91 -100
  2. package/dist/ably-ai-transport.js +1553 -1238
  3. package/dist/ably-ai-transport.js.map +1 -1
  4. package/dist/ably-ai-transport.umd.cjs +1 -1
  5. package/dist/ably-ai-transport.umd.cjs.map +1 -1
  6. package/dist/constants.d.ts +116 -42
  7. package/dist/core/agent.d.ts +29 -0
  8. package/dist/core/codec/decoder.d.ts +20 -23
  9. package/dist/core/codec/encoder.d.ts +11 -8
  10. package/dist/core/codec/index.d.ts +1 -2
  11. package/dist/core/codec/lifecycle-tracker.d.ts +10 -9
  12. package/dist/core/codec/types.d.ts +407 -115
  13. package/dist/core/transport/agent-session.d.ts +10 -0
  14. package/dist/core/transport/branch-chain.d.ts +43 -0
  15. package/dist/core/transport/client-session.d.ts +13 -0
  16. package/dist/core/transport/decode-fold.d.ts +47 -0
  17. package/dist/core/transport/headers.d.ts +96 -18
  18. package/dist/core/transport/index.d.ts +5 -6
  19. package/dist/core/transport/internal/bounded-map.d.ts +20 -0
  20. package/dist/core/transport/invocation.d.ts +74 -0
  21. package/dist/core/transport/load-conversation.d.ts +128 -0
  22. package/dist/core/transport/load-history.d.ts +39 -0
  23. package/dist/core/transport/pipe-stream.d.ts +9 -9
  24. package/dist/core/transport/run-manager.d.ts +78 -0
  25. package/dist/core/transport/tree.d.ts +373 -109
  26. package/dist/core/transport/types/agent.d.ts +353 -0
  27. package/dist/core/transport/types/client.d.ts +168 -0
  28. package/dist/core/transport/types/shared.d.ts +24 -0
  29. package/dist/core/transport/types/tree.d.ts +315 -0
  30. package/dist/core/transport/types/view.d.ts +222 -0
  31. package/dist/core/transport/types.d.ts +13 -553
  32. package/dist/core/transport/view.d.ts +272 -84
  33. package/dist/errors.d.ts +21 -10
  34. package/dist/index.d.ts +6 -8
  35. package/dist/logger.d.ts +12 -0
  36. package/dist/react/ably-ai-transport-react.js +976 -990
  37. package/dist/react/ably-ai-transport-react.js.map +1 -1
  38. package/dist/react/ably-ai-transport-react.umd.cjs +1 -1
  39. package/dist/react/ably-ai-transport-react.umd.cjs.map +1 -1
  40. package/dist/react/contexts/client-session-context.d.ts +36 -0
  41. package/dist/react/contexts/client-session-provider.d.ts +53 -0
  42. package/dist/react/create-session-hooks.d.ts +116 -0
  43. package/dist/react/index.d.ts +12 -12
  44. package/dist/react/internal/use-resolved-session.d.ts +36 -0
  45. package/dist/react/use-ably-messages.d.ts +17 -14
  46. package/dist/react/use-client-session.d.ts +81 -0
  47. package/dist/react/use-create-view.d.ts +14 -13
  48. package/dist/react/use-tree.d.ts +30 -15
  49. package/dist/react/use-view.d.ts +82 -51
  50. package/dist/utils.d.ts +32 -23
  51. package/dist/vercel/ably-ai-transport-vercel.js +2573 -2086
  52. package/dist/vercel/ably-ai-transport-vercel.js.map +1 -1
  53. package/dist/vercel/ably-ai-transport-vercel.umd.cjs +1 -1
  54. package/dist/vercel/ably-ai-transport-vercel.umd.cjs.map +1 -1
  55. package/dist/vercel/codec/decoder.d.ts +5 -18
  56. package/dist/vercel/codec/encoder.d.ts +6 -36
  57. package/dist/vercel/codec/events.d.ts +51 -0
  58. package/dist/vercel/codec/index.d.ts +24 -12
  59. package/dist/vercel/codec/reducer.d.ts +144 -0
  60. package/dist/vercel/codec/tool-transitions.d.ts +2 -2
  61. package/dist/vercel/index.d.ts +4 -5
  62. package/dist/vercel/react/ably-ai-transport-vercel-react.js +3907 -3266
  63. package/dist/vercel/react/ably-ai-transport-vercel-react.js.map +1 -1
  64. package/dist/vercel/react/ably-ai-transport-vercel-react.umd.cjs +33 -8
  65. package/dist/vercel/react/ably-ai-transport-vercel-react.umd.cjs.map +1 -1
  66. package/dist/vercel/react/contexts/chat-transport-context.d.ts +7 -6
  67. package/dist/vercel/react/contexts/chat-transport-provider.d.ts +53 -41
  68. package/dist/vercel/react/index.d.ts +1 -2
  69. package/dist/vercel/react/use-chat-transport.d.ts +30 -26
  70. package/dist/vercel/react/use-message-sync.d.ts +17 -30
  71. package/dist/vercel/run-end-reason.d.ts +29 -0
  72. package/dist/vercel/transport/chat-transport.d.ts +43 -24
  73. package/dist/vercel/transport/index.d.ts +25 -21
  74. package/dist/vercel/transport/run-output-stream.d.ts +56 -0
  75. package/dist/version.d.ts +2 -0
  76. package/package.json +30 -23
  77. package/src/constants.ts +124 -51
  78. package/src/core/agent.ts +68 -0
  79. package/src/core/codec/decoder.ts +71 -98
  80. package/src/core/codec/encoder.ts +113 -65
  81. package/src/core/codec/index.ts +13 -6
  82. package/src/core/codec/lifecycle-tracker.ts +10 -9
  83. package/src/core/codec/types.ts +436 -120
  84. package/src/core/transport/agent-session.ts +1344 -0
  85. package/src/core/transport/branch-chain.ts +58 -0
  86. package/src/core/transport/client-session.ts +775 -0
  87. package/src/core/transport/decode-fold.ts +91 -0
  88. package/src/core/transport/headers.ts +181 -22
  89. package/src/core/transport/index.ts +25 -26
  90. package/src/core/transport/internal/bounded-map.ts +27 -0
  91. package/src/core/transport/invocation.ts +98 -0
  92. package/src/core/transport/load-conversation.ts +355 -0
  93. package/src/core/transport/load-history.ts +269 -0
  94. package/src/core/transport/pipe-stream.ts +54 -39
  95. package/src/core/transport/run-manager.ts +249 -0
  96. package/src/core/transport/tree.ts +926 -308
  97. package/src/core/transport/types/agent.ts +407 -0
  98. package/src/core/transport/types/client.ts +211 -0
  99. package/src/core/transport/types/shared.ts +27 -0
  100. package/src/core/transport/types/tree.ts +344 -0
  101. package/src/core/transport/types/view.ts +259 -0
  102. package/src/core/transport/types.ts +13 -706
  103. package/src/core/transport/view.ts +864 -433
  104. package/src/errors.ts +22 -9
  105. package/src/event-emitter.ts +3 -2
  106. package/src/index.ts +52 -41
  107. package/src/logger.ts +14 -1
  108. package/src/react/contexts/client-session-context.ts +41 -0
  109. package/src/react/contexts/client-session-provider.tsx +186 -0
  110. package/src/react/create-session-hooks.ts +141 -0
  111. package/src/react/index.ts +23 -13
  112. package/src/react/internal/use-resolved-session.ts +63 -0
  113. package/src/react/use-ably-messages.ts +32 -22
  114. package/src/react/use-client-session.ts +201 -0
  115. package/src/react/use-create-view.ts +33 -29
  116. package/src/react/use-tree.ts +61 -30
  117. package/src/react/use-view.ts +139 -97
  118. package/src/utils.ts +63 -45
  119. package/src/vercel/codec/decoder.ts +336 -258
  120. package/src/vercel/codec/encoder.ts +343 -205
  121. package/src/vercel/codec/events.ts +87 -0
  122. package/src/vercel/codec/index.ts +60 -13
  123. package/src/vercel/codec/reducer.ts +977 -0
  124. package/src/vercel/codec/tool-transitions.ts +2 -2
  125. package/src/vercel/index.ts +6 -19
  126. package/src/vercel/react/contexts/chat-transport-context.ts +7 -6
  127. package/src/vercel/react/contexts/chat-transport-provider.tsx +87 -59
  128. package/src/vercel/react/index.ts +3 -5
  129. package/src/vercel/react/use-chat-transport.ts +47 -49
  130. package/src/vercel/react/use-message-sync.ts +80 -39
  131. package/src/vercel/run-end-reason.ts +78 -0
  132. package/src/vercel/transport/chat-transport.ts +392 -98
  133. package/src/vercel/transport/index.ts +39 -38
  134. package/src/vercel/transport/run-output-stream.ts +170 -0
  135. package/src/version.ts +2 -0
  136. package/dist/core/transport/client-transport.d.ts +0 -10
  137. package/dist/core/transport/decode-history.d.ts +0 -43
  138. package/dist/core/transport/server-transport.d.ts +0 -7
  139. package/dist/core/transport/stream-router.d.ts +0 -29
  140. package/dist/core/transport/turn-manager.d.ts +0 -37
  141. package/dist/react/contexts/transport-context.d.ts +0 -31
  142. package/dist/react/contexts/transport-provider.d.ts +0 -49
  143. package/dist/react/create-transport-hooks.d.ts +0 -124
  144. package/dist/react/use-active-turns.d.ts +0 -12
  145. package/dist/react/use-client-transport.d.ts +0 -80
  146. package/dist/vercel/codec/accumulator.d.ts +0 -21
  147. package/dist/vercel/react/use-staged-add-tool-approval-response.d.ts +0 -30
  148. package/dist/vercel/tool-approvals.d.ts +0 -124
  149. package/dist/vercel/tool-events.d.ts +0 -26
  150. package/src/core/transport/client-transport.ts +0 -977
  151. package/src/core/transport/decode-history.ts +0 -485
  152. package/src/core/transport/server-transport.ts +0 -612
  153. package/src/core/transport/stream-router.ts +0 -136
  154. package/src/core/transport/turn-manager.ts +0 -165
  155. package/src/react/contexts/transport-context.ts +0 -37
  156. package/src/react/contexts/transport-provider.tsx +0 -164
  157. package/src/react/create-transport-hooks.ts +0 -144
  158. package/src/react/use-active-turns.ts +0 -72
  159. package/src/react/use-client-transport.ts +0 -197
  160. package/src/vercel/codec/accumulator.ts +0 -588
  161. package/src/vercel/react/use-staged-add-tool-approval-response.ts +0 -87
  162. package/src/vercel/tool-approvals.ts +0 -380
  163. package/src/vercel/tool-events.ts +0 -53
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * Shared tool part transition logic for the Vercel AI SDK codec.
3
3
  *
4
- * Extracted from the accumulator so the tool output state transition logic
5
- * lives in one place, reusable by the accumulator and any other callers.
4
+ * Keeps the tool output state transition logic in one place, reusable by the
5
+ * Vercel codec reducer and any other callers.
6
6
  */
7
7
 
8
8
  import type * as AI from 'ai';
@@ -1,4 +1,5 @@
1
1
  // Vercel AI SDK codec
2
+ export type { VercelInput, VercelOutput, VercelProjection } from './codec/index.js';
2
3
  export { UIMessageCodec } from './codec/index.js';
3
4
 
4
5
  // Vercel AI SDK transport wrappers (pre-bound to UIMessageCodec)
@@ -6,24 +7,10 @@ export type {
6
7
  ChatTransport,
7
8
  ChatTransportOptions,
8
9
  SendMessagesRequestContext,
9
- VercelClientTransportOptions,
10
- VercelServerTransportOptions,
10
+ VercelAgentSessionOptions,
11
+ VercelClientSessionOptions,
11
12
  } from './transport/index.js';
12
- export { createChatTransport, createClientTransport, createServerTransport } from './transport/index.js';
13
+ export { createAgentSession, createChatTransport, createClientSession } from './transport/index.js';
13
14
 
14
- // Server-side tool result merge helper
15
- export { applyToolEventsToHistory } from './tool-events.js';
16
-
17
- // Server-side tool approval helpers
18
- export type {
19
- PrepareApprovalTurnOptions,
20
- PrepareApprovalTurnResult,
21
- StreamResponseWithApprovalRedirectOptions,
22
- ToolApprovalDecision,
23
- } from './tool-approvals.js';
24
- export {
25
- applyToolApprovalsToHistory,
26
- extractApprovalDecisionsFromHistory,
27
- prepareApprovalTurn,
28
- streamResponseWithApprovalRedirect,
29
- } from './tool-approvals.js';
15
+ // Vercel-shaped helpers
16
+ export { vercelRunOutcome } from './run-end-reason.js';
@@ -2,18 +2,19 @@ import type * as Ably from 'ably';
2
2
  import type * as AI from 'ai';
3
3
  import { createContext } from 'react';
4
4
 
5
- import type { ClientTransport } from '../../../core/transport/types.js';
5
+ import type { ClientSession } from '../../../core/transport/types.js';
6
+ import type { VercelInput, VercelOutput, VercelProjection } from '../../codec/index.js';
6
7
  import type { ChatTransport } from '../../transport/chat-transport.js';
7
8
 
8
9
  /**
9
10
  * A single entry in the chat transport registry, holding both the
10
- * underlying {@link ClientTransport} and the {@link ChatTransport} wrapping it.
11
+ * underlying {@link ClientSession} and the {@link ChatTransport} wrapping it.
11
12
  */
12
13
  export interface ChatTransportSlot {
13
- /** The underlying client transport used to create the chat transport. */
14
- readonly transport: ClientTransport<AI.UIMessageChunk, AI.UIMessage>;
15
- /** Construction error from the underlying {@link ClientTransport}, or `undefined` on success. */
16
- readonly transportError: Ably.ErrorInfo | undefined;
14
+ /** The underlying client session used to create the chat transport. */
15
+ readonly session: ClientSession<VercelInput, VercelOutput, VercelProjection, AI.UIMessage>;
16
+ /** Construction error from the underlying {@link ClientSession}, or `undefined` on success. */
17
+ readonly sessionError?: Ably.ErrorInfo | undefined;
17
18
  /** The chat transport adapter for use with Vercel's useChat hook. */
18
19
  readonly chatTransport: ChatTransport;
19
20
  }
@@ -1,92 +1,100 @@
1
1
  /**
2
- * ChatTransportProvider: creates a ChatTransport from a ClientTransport and makes it
2
+ * ChatTransportProvider: creates a ChatTransport from a ClientSession and makes it
3
3
  * available to descendants via ChatTransportContext.
4
4
  *
5
- * Wraps children with TransportProvider (using UIMessageCodec) so the Ably channel
6
- * lifecycle is managed in one place. An inner component reads the ClientTransport
7
- * from NearestTransportContext and creates the ChatTransport once on first render
8
- * (via useRef).
5
+ * Wraps children with ClientSessionProvider (using UIMessageCodec). The
6
+ * surrounding `<AblyProvider>` supplies the Realtime client; the session
7
+ * resolves the channel from `channelName` itself. An inner component reads
8
+ * the ClientSession via useClientSession() and creates the ChatTransport
9
+ * via useMemo, keyed on the session and transport options.
9
10
  *
10
- * The ChatTransport is NOT closed on unmount — the underlying ClientTransport
11
- * lifecycle is managed by the wrapping TransportProvider. Auto-closing would break
12
- * React Strict Mode, and ChatTransport.close() delegates to ClientTransport.close()
13
- * which TransportProvider already calls.
11
+ * The ChatTransport is NOT closed on unmount — the underlying ClientSession
12
+ * lifecycle is managed by the wrapping ClientSessionProvider. Auto-closing would break
13
+ * React Strict Mode, and ChatTransport.close() delegates to ClientSession.close()
14
+ * which ClientSessionProvider already calls.
14
15
  *
15
16
  * Multiple ChatTransportProviders can be nested using distinct channelNames.
16
- * Each provider merges its transport into the parent registry, so descendants
17
- * can access all registered transports via useChatTransport({ channelName }).
17
+ * Each provider merges its session into the parent registry, so descendants
18
+ * can access all registered sessions via useChatTransport({ channelName }).
18
19
  */
19
20
 
20
21
  import type * as AI from 'ai';
21
22
  import { type PropsWithChildren, type ReactNode, useContext, useMemo } from 'react';
22
23
 
23
- import { createTransportHooks, type TransportProviderProps } from '../../../react/index.js';
24
- import { UIMessageCodec } from '../../codec/index.js';
25
- import { type ChatTransportOptions, DEFAULT_VERCEL_API } from '../../transport/index.js';
24
+ import { type ClientSessionProviderProps, createSessionHooks } from '../../../react/index.js';
25
+ import { UIMessageCodec, type VercelInput, type VercelOutput, type VercelProjection } from '../../codec/index.js';
26
+ import type { ChatTransportOptions } from '../../transport/index.js';
26
27
  import { createChatTransport } from '../../transport/index.js';
27
28
  import type { ChatTransportSlot } from './chat-transport-context.js';
28
29
  import { ChatTransportContext } from './chat-transport-context.js';
29
30
 
30
- export const {
31
- TransportProvider,
32
- useAblyMessages,
33
- useActiveTurns,
34
- useClientTransport,
35
- useCreateView,
36
- useTree,
37
- useView,
38
- } = createTransportHooks<AI.UIMessageChunk, AI.UIMessage>();
31
+ export const { ClientSessionProvider, useAblyMessages, useClientSession, useCreateView, useTree, useView } =
32
+ createSessionHooks<VercelInput, VercelOutput, VercelProjection, AI.UIMessage>();
39
33
 
40
- type CoreTransportProviderProps = Omit<TransportProviderProps<AI.UIMessageChunk, AI.UIMessage>, 'codec' | 'api'> &
41
- Partial<Pick<TransportProviderProps<AI.UIMessageChunk, AI.UIMessage>, 'api'>>;
34
+ type CoreClientSessionProviderProps = Omit<
35
+ ClientSessionProviderProps<VercelInput, VercelOutput, VercelProjection, AI.UIMessage>,
36
+ 'codec'
37
+ >;
42
38
 
43
39
  /**
44
40
  * Props for {@link ChatTransportProvider}.
45
41
  *
46
- * All {@link TransportProviderProps} for Vercel types except `codec` (baked as UIMessageCodec),
47
- * plus `chatOptions` for customizing chat request construction.
42
+ * All {@link ClientSessionProviderProps} for Vercel types except `codec` (baked as UIMessageCodec),
43
+ * plus the transport-owned invocation POST options (`api` / `credentials` / `fetch`) and
44
+ * `chatOptions` for customizing chat request construction.
48
45
  */
49
- export interface ChatTransportProviderProps extends CoreTransportProviderProps {
46
+ export interface ChatTransportProviderProps extends CoreClientSessionProviderProps {
47
+ /** Endpoint the chat transport POSTs the invocation to, to wake the agent. Default `/api/chat`. */
48
+ api?: string;
49
+ /** Fetch credentials mode for the invocation POST. */
50
+ credentials?: RequestCredentials;
51
+ /** Custom fetch implementation for the invocation POST. Defaults to `globalThis.fetch`. */
52
+ fetch?: typeof globalThis.fetch;
50
53
  /**
51
- * Optional hooks for customizing chat request construction (e.g. prepareSendMessagesRequest).
54
+ * Optional transport options for customizing chat request construction (e.g. the `prepareSendMessagesRequest` hook).
52
55
  * Must be stable across renders — wrap in `useMemo` or define outside the component.
53
56
  * A new object reference triggers ChatTransport recreation.
57
+ * If this object also sets `api`/`credentials`/`fetch`, the dedicated top-level props of the same name take precedence.
54
58
  */
55
59
  chatOptions?: ChatTransportOptions;
56
60
  }
57
61
 
58
62
  const ChatTransportProviderInner = ({
59
63
  channelName,
60
- chatOptions,
64
+ chatTransportOptions,
61
65
  children,
62
66
  }: {
63
67
  channelName: string;
64
- chatOptions?: ChatTransportOptions;
68
+ chatTransportOptions: ChatTransportOptions;
65
69
  children: ReactNode;
66
70
  }) => {
67
- const { transport, transportError } = useClientTransport();
71
+ const { session, sessionError } = useClientSession();
68
72
  const { providers: parentProviders } = useContext(ChatTransportContext);
69
- const chatTransport = useMemo(() => createChatTransport(transport, chatOptions), [transport, chatOptions]);
73
+ const chatTransport = useMemo(
74
+ () => createChatTransport(session, chatTransportOptions),
75
+ [session, chatTransportOptions],
76
+ );
70
77
  const contextValue = useMemo(() => {
71
- const slot: ChatTransportSlot = { transport, transportError, chatTransport };
78
+ const slot: ChatTransportSlot = { session, sessionError, chatTransport };
72
79
  return {
73
80
  nearest: slot,
74
81
  providers: { ...parentProviders, [channelName]: slot },
75
82
  };
76
- }, [channelName, parentProviders, chatTransport, transport, transportError]);
83
+ }, [channelName, parentProviders, chatTransport, session, sessionError]);
77
84
 
78
85
  return <ChatTransportContext.Provider value={contextValue}>{children}</ChatTransportContext.Provider>;
79
86
  };
80
87
 
81
88
  /**
82
- * Provide a {@link ChatTransport} and its underlying {@link ClientTransport} to descendant components.
89
+ * Provide a {@link ChatTransport} and its underlying {@link ClientSession} to descendant components.
83
90
  *
84
- * Wraps children with Ably's `ChannelProvider` (via `TransportProvider`) using `channelName`,
85
- * creates a {@link ClientTransport} with UIMessageCodec, wraps it in a {@link ChatTransport},
91
+ * Wraps children with `ClientSessionProvider` using `channelName` (the Realtime
92
+ * client is read from the surrounding `<AblyProvider>`), creates a
93
+ * {@link ClientSession} with UIMessageCodec, wraps it in a {@link ChatTransport},
86
94
  * and registers the full slot in `ChatTransportContext` under `channelName`. Descendants call
87
- * {@link useChatTransport} with the same `channelName` to access both transports.
95
+ * {@link useChatTransport} with the same `channelName` to access both.
88
96
  *
89
- * `useClientTransport` is also available inside this provider's subtree.
97
+ * `useClientSession` is also available inside this provider's subtree.
90
98
  *
91
99
  * ```tsx
92
100
  * <ChatTransportProvider channelName="ai:demo">
@@ -94,29 +102,49 @@ const ChatTransportProviderInner = ({
94
102
  * </ChatTransportProvider>
95
103
  *
96
104
  * // Inside Chat:
97
- * const { chatTransport, transport } = useChatTransport();
98
- * const { transport } = useClientTransport(); // also available
105
+ * const { chatTransport, session } = useChatTransport();
106
+ * const { session } = useClientSession(); // also available
99
107
  * ```
100
- * @param props - Provider configuration including `channelName`, optional `chatOptions`, and all other transport options.
108
+ * @param props - Provider configuration including `channelName`, the invocation POST options (`api` / `credentials` / `fetch`), optional `chatOptions`, and all other session options.
109
+ * @param props.api - Endpoint the chat transport POSTs the invocation to. Default `/api/chat`.
110
+ * @param props.credentials - Fetch credentials mode for the invocation POST.
111
+ * @param props.fetch - Custom fetch implementation for the invocation POST.
101
112
  * @param props.chatOptions - Optional hooks for customizing chat request construction. Must be stable (memoized) — a new reference recreates the ChatTransport.
102
- * @param props.children - Descendant components that consume the transport via hooks.
103
- * @returns A React element wrapping children with ChannelProvider, TransportContext, and ChatTransportContext.
113
+ * @param props.children - Descendant components that consume the chat transport via hooks.
114
+ * @returns A React element wrapping children with ClientSessionContext and ChatTransportContext.
104
115
  */
105
116
  export const ChatTransportProvider = ({
117
+ api,
118
+ credentials,
119
+ fetch,
106
120
  chatOptions,
107
121
  children,
108
- ...transportProps
109
- }: ChatTransportProviderProps & PropsWithChildren): ReactNode => (
110
- <TransportProvider
111
- {...transportProps}
112
- api={transportProps.api ?? DEFAULT_VERCEL_API}
113
- codec={UIMessageCodec}
114
- >
115
- <ChatTransportProviderInner
116
- channelName={transportProps.channelName}
117
- chatOptions={chatOptions}
122
+ ...sessionProps
123
+ }: ChatTransportProviderProps & PropsWithChildren): ReactNode => {
124
+ // Fold the transport-owned POST options into a single ChatTransportOptions.
125
+ // Memoized so the ChatTransport isn't recreated each render — createChatTransport
126
+ // is keyed on this object's identity.
127
+ const chatTransportOptions = useMemo<ChatTransportOptions>(
128
+ () => ({
129
+ ...chatOptions,
130
+ ...(api !== undefined && { api }),
131
+ ...(credentials !== undefined && { credentials }),
132
+ ...(fetch !== undefined && { fetch }),
133
+ }),
134
+ [api, credentials, fetch, chatOptions],
135
+ );
136
+
137
+ return (
138
+ <ClientSessionProvider
139
+ {...sessionProps}
140
+ codec={UIMessageCodec}
118
141
  >
119
- {children}
120
- </ChatTransportProviderInner>
121
- </TransportProvider>
122
- );
142
+ <ChatTransportProviderInner
143
+ channelName={sessionProps.channelName}
144
+ chatTransportOptions={chatTransportOptions}
145
+ >
146
+ {children}
147
+ </ChatTransportProviderInner>
148
+ </ClientSessionProvider>
149
+ );
150
+ };
@@ -1,12 +1,11 @@
1
- // Vercel-specific React hooks
1
+ // Vercel-specific React entry point: providers, hooks, and their types
2
2
  export type { ChatTransport } from '../transport/chat-transport.js';
3
3
  export type { ChatTransportProviderProps } from './contexts/chat-transport-provider.js';
4
4
  export {
5
5
  ChatTransportProvider,
6
- TransportProvider,
6
+ ClientSessionProvider,
7
7
  useAblyMessages,
8
- useActiveTurns,
9
- useClientTransport,
8
+ useClientSession,
10
9
  useCreateView,
11
10
  useTree,
12
11
  useView,
@@ -15,4 +14,3 @@ export type { ChatTransportHandle, UseChatTransportOptions } from './use-chat-tr
15
14
  export { useChatTransport } from './use-chat-transport.js';
16
15
  export type { UseMessageSyncOptions } from './use-message-sync.js';
17
16
  export { useMessageSync } from './use-message-sync.js';
18
- export { useStagedAddToolApprovalResponse } from './use-staged-add-tool-approval-response.js';
@@ -1,47 +1,43 @@
1
1
  /**
2
- * useChatTransport: reads a ChatTransport and its underlying ClientTransport from
2
+ * useChatTransport: reads a ChatTransport and its underlying ClientSession from
3
3
  * the nearest ChatTransportProvider.
4
4
  *
5
- * The transport is created by ChatTransportProvider, which also wraps the subtree
6
- * with TransportProvider and Ably's ChannelProvider. This hook is a thin context
7
- * reader it does not create or manage any transport state.
5
+ * The chat transport is created by ChatTransportProvider, which wraps the subtree
6
+ * with ClientSessionProvider. The Ably Realtime client is read from the
7
+ * surrounding `<AblyProvider>`. This hook is a thin context reader it does
8
+ * not create or manage any session/transport state.
8
9
  *
9
10
  * Pass `channelName` to look up a specific provider by name. Omit to use the nearest
10
11
  * provider in the tree. Pass `skip: true` to defer (e.g. when auth is not yet resolved)
11
- * — returns stub transports whose properties throw with a descriptive error.
12
+ * — returns stubs whose properties throw with a descriptive error.
12
13
  */
13
14
 
14
15
  import * as Ably from 'ably';
15
16
  import type * as AI from 'ai';
16
17
  import { useContext } from 'react';
17
18
 
18
- import type { ClientTransport, Tree, View } from '../../core/transport/types.js';
19
+ import type { ClientSession, Tree, View } from '../../core/transport/types.js';
19
20
  import { ErrorCode } from '../../errors.js';
21
+ import type { VercelInput, VercelOutput, VercelProjection } from '../codec/index.js';
20
22
  import type { ChatTransport } from '../transport/index.js';
21
23
  import { ChatTransportContext } from './contexts/chat-transport-context.js';
22
24
 
23
- const SKIPPED_CLIENT_TRANSPORT: ClientTransport<AI.UIMessageChunk, AI.UIMessage> = {
24
- get tree(): Tree<AI.UIMessage> {
25
+ const SKIPPED_CLIENT_SESSION: ClientSession<VercelInput, VercelOutput, VercelProjection, AI.UIMessage> = {
26
+ get tree(): Tree<VercelOutput, VercelProjection> {
25
27
  throw new Ably.ErrorInfo('unable to access tree; hook is skipped', ErrorCode.InvalidArgument, 400);
26
28
  },
27
- get view(): View<AI.UIMessageChunk, AI.UIMessage> {
29
+ get view(): View<VercelInput, AI.UIMessage> {
28
30
  throw new Ably.ErrorInfo('unable to access view; hook is skipped', ErrorCode.InvalidArgument, 400);
29
31
  },
30
- createView: (): View<AI.UIMessageChunk, AI.UIMessage> => {
32
+ connect: () => {
33
+ throw new Ably.ErrorInfo('unable to connect; hook is skipped', ErrorCode.InvalidArgument, 400);
34
+ },
35
+ createView: (): View<VercelInput, AI.UIMessage> => {
31
36
  throw new Ably.ErrorInfo('unable to create view; hook is skipped', ErrorCode.InvalidArgument, 400);
32
37
  },
33
38
  cancel: () => {
34
39
  throw new Ably.ErrorInfo('unable to cancel; hook is skipped', ErrorCode.InvalidArgument, 400);
35
40
  },
36
- stageEvents: () => {
37
- throw new Ably.ErrorInfo('unable to stage events; hook is skipped', ErrorCode.InvalidArgument, 400);
38
- },
39
- stageMessage: () => {
40
- throw new Ably.ErrorInfo('unable to stage message; hook is skipped', ErrorCode.InvalidArgument, 400);
41
- },
42
- waitForTurn: () => {
43
- throw new Ably.ErrorInfo('unable to wait for turn; hook is skipped', ErrorCode.InvalidArgument, 400);
44
- },
45
41
  on: () => {
46
42
  throw new Ably.ErrorInfo('unable to subscribe; hook is skipped', ErrorCode.InvalidArgument, 400);
47
43
  },
@@ -76,76 +72,78 @@ const SKIPPED_CHAT_TRANSPORT: ChatTransport = {
76
72
  export interface UseChatTransportOptions {
77
73
  /** Channel name to look up; omit to use the nearest {@link ChatTransportProvider}. */
78
74
  channelName?: string;
79
- /** When `true`, return stub transports that throw on any access. */
75
+ /** When `true`, return stubs that throw on any access. */
80
76
  skip?: boolean;
81
77
  }
82
78
 
83
79
  /**
84
80
  * The value returned by {@link useChatTransport}.
85
- * Provides both the underlying {@link ClientTransport} and the {@link ChatTransport}
81
+ * Provides both the underlying {@link ClientSession} and the {@link ChatTransport}
86
82
  * adapter for Vercel's useChat hook.
87
83
  */
88
84
  export interface ChatTransportHandle {
89
85
  /**
90
- * The underlying client transport, also available via {@link useClientTransport}.
91
- * A throwing stub when `skip` is `true`, when no matching {@link TransportProvider}
92
- * was found in the tree, or when transport construction failed. Check `transportError` before use.
86
+ * The underlying client session, also available via {@link useClientSession}.
87
+ * A throwing stub when `skip` is `true`, when no matching {@link ClientSessionProvider}
88
+ * was found in the tree, or when session construction failed. Check `sessionError` before use.
93
89
  */
94
- transport: ClientTransport<AI.UIMessageChunk, AI.UIMessage>;
90
+ session: ClientSession<VercelInput, VercelOutput, VercelProjection, AI.UIMessage>;
95
91
 
96
92
  /**
97
93
  * The chat transport adapter for use with Vercel's `useChat` hook.
98
94
  *
99
- * A throwing stub when `skip` is `true`, when no matching
100
- * {@link ChatTransportProvider} was found in the tree, or when the underlying
101
- * {@link ClientTransport} construction failed. Check both `chatTransportError`
102
- * and `transportError` before use.
95
+ * A throwing stub when `skip` is `true` or when no matching
96
+ * {@link ChatTransportProvider} was found in the tree. When a provider is found
97
+ * but the underlying {@link ClientSession} failed to construct, this is the real
98
+ * transport and `sessionError` is set instead. Check `chatTransportError` and
99
+ * `sessionError` before use.
103
100
  */
104
101
  chatTransport: ChatTransport;
105
102
 
106
103
  /**
107
- * Set when no matching {@link TransportProvider} was found, when transport
104
+ * Set when no matching {@link ClientSessionProvider} was found, when session
108
105
  * construction failed, and `skip` is `false`.
109
- * `undefined` when the transport resolved successfully or when `skip` is `true`.
106
+ * `undefined` when the session resolved successfully or when `skip` is `true`.
110
107
  */
111
- transportError?: Ably.ErrorInfo | undefined;
108
+ sessionError?: Ably.ErrorInfo | undefined;
112
109
  /**
113
- * Set when no matching {@link ChatTransportProvider} was found or when transport
114
- * construction failed, and `skip` is `false`.
115
- * `undefined` when the transport resolved successfully or when `skip` is `true`.
110
+ * Set only when no matching {@link ChatTransportProvider} was found and `skip` is
111
+ * `false`.
112
+ * `undefined` when the chat transport resolved successfully (even if session
113
+ * construction failed — see `sessionError`) or when `skip` is `true`.
116
114
  */
117
115
  chatTransportError?: Ably.ErrorInfo | undefined;
118
116
  }
119
117
 
120
118
  /**
121
- * Access a {@link ChatTransport} and {@link ClientTransport} from the nearest {@link ChatTransportProvider}.
119
+ * Access a {@link ChatTransport} and {@link ClientSession} from the nearest {@link ChatTransportProvider}.
122
120
  *
123
121
  * When `channelName` is omitted, the innermost `ChatTransportProvider` in the tree is used.
124
- * When `skip` is `true`, returns stub transports whose every property and method throws
122
+ * When `skip` is `true`, returns stubs whose every property and method throws
125
123
  * an {@link Ably.ErrorInfo} — safe to hold in state before conditions are ready.
126
124
  * When no provider is found, returns stubs with `chatTransportError` set instead of throwing.
127
- * @param props - Options for selecting the transport.
125
+ * @param props - Options for selecting the chat transport.
128
126
  * @param props.channelName - The channel name passed to the enclosing `ChatTransportProvider`. Omit to use the nearest.
129
127
  * @param props.skip - When `true`, return stubs that throw on any access instead of reading from context.
130
- * @returns The `ChatTransportHandle` containing both the chat transport adapter and the underlying client transport.
128
+ * @returns The `ChatTransportHandle` containing both the chat transport adapter and the underlying client session.
131
129
  */
132
130
  export const useChatTransport = ({ channelName, skip }: UseChatTransportOptions = {}): ChatTransportHandle => {
133
131
  const { nearest, providers } = useContext(ChatTransportContext);
134
132
 
135
133
  if (skip) {
136
- return { transport: SKIPPED_CLIENT_TRANSPORT, chatTransport: SKIPPED_CHAT_TRANSPORT };
134
+ return { session: SKIPPED_CLIENT_SESSION, chatTransport: SKIPPED_CHAT_TRANSPORT };
137
135
  }
138
136
 
139
137
  if (channelName !== undefined) {
140
138
  const slot = providers[channelName];
141
139
  if (slot) {
142
- return { transport: slot.transport, chatTransport: slot.chatTransport, transportError: slot.transportError };
140
+ return { session: slot.session, chatTransport: slot.chatTransport, sessionError: slot.sessionError };
143
141
  }
144
142
  return {
145
- transport: SKIPPED_CLIENT_TRANSPORT,
143
+ session: SKIPPED_CLIENT_SESSION,
146
144
  chatTransport: SKIPPED_CHAT_TRANSPORT,
147
- transportError: new Ably.ErrorInfo(
148
- `unable to use client transport; no TransportProvider found for channelName "${channelName}"`,
145
+ sessionError: new Ably.ErrorInfo(
146
+ `unable to use client session; no ClientSessionProvider found for channelName "${channelName}"`,
149
147
  ErrorCode.BadRequest,
150
148
  400,
151
149
  ),
@@ -159,17 +157,17 @@ export const useChatTransport = ({ channelName, skip }: UseChatTransportOptions
159
157
 
160
158
  if (nearest) {
161
159
  return {
162
- transport: nearest.transport,
160
+ session: nearest.session,
163
161
  chatTransport: nearest.chatTransport,
164
- transportError: nearest.transportError,
162
+ sessionError: nearest.sessionError,
165
163
  };
166
164
  }
167
165
 
168
166
  return {
169
- transport: SKIPPED_CLIENT_TRANSPORT,
167
+ session: SKIPPED_CLIENT_SESSION,
170
168
  chatTransport: SKIPPED_CHAT_TRANSPORT,
171
- transportError: new Ably.ErrorInfo(
172
- 'unable to use transport; no TransportProvider found in the tree',
169
+ sessionError: new Ably.ErrorInfo(
170
+ 'unable to use session; no ClientSessionProvider found in the tree',
173
171
  ErrorCode.BadRequest,
174
172
  400,
175
173
  ),