@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,16 +1,17 @@
1
- import { ClientTransport } from '../../../core/transport/types.js';
1
+ import { ClientSession } from '../../../core/transport/types.js';
2
+ import { VercelInput, VercelOutput, VercelProjection } from '../../codec/index.js';
2
3
  import { ChatTransport } from '../../transport/chat-transport.js';
3
4
  import type * as Ably from 'ably';
4
5
  import type * as AI from 'ai';
5
6
  /**
6
7
  * A single entry in the chat transport registry, holding both the
7
- * underlying {@link ClientTransport} and the {@link ChatTransport} wrapping it.
8
+ * underlying {@link ClientSession} and the {@link ChatTransport} wrapping it.
8
9
  */
9
10
  export interface ChatTransportSlot {
10
- /** The underlying client transport used to create the chat transport. */
11
- readonly transport: ClientTransport<AI.UIMessageChunk, AI.UIMessage>;
12
- /** Construction error from the underlying {@link ClientTransport}, or `undefined` on success. */
13
- readonly transportError: Ably.ErrorInfo | undefined;
11
+ /** The underlying client session used to create the chat transport. */
12
+ readonly session: ClientSession<VercelInput, VercelOutput, VercelProjection, AI.UIMessage>;
13
+ /** Construction error from the underlying {@link ClientSession}, or `undefined` on success. */
14
+ readonly sessionError?: Ably.ErrorInfo | undefined;
14
15
  /** The chat transport adapter for use with Vercel's useChat hook. */
15
16
  readonly chatTransport: ChatTransport;
16
17
  }
@@ -1,70 +1,79 @@
1
1
  import { PropsWithChildren, ReactNode } from 'react';
2
- import { TransportProviderProps } from '../../../react/index.js';
2
+ import { ClientSessionProviderProps } from '../../../react/index.js';
3
+ import { VercelInput, VercelOutput, VercelProjection } from '../../codec/index.js';
3
4
  import { ChatTransportOptions } from '../../transport/index.js';
4
5
  /**
5
- * ChatTransportProvider: creates a ChatTransport from a ClientTransport and makes it
6
+ * ChatTransportProvider: creates a ChatTransport from a ClientSession and makes it
6
7
  * available to descendants via ChatTransportContext.
7
8
  *
8
- * Wraps children with TransportProvider (using UIMessageCodec) so the Ably channel
9
- * lifecycle is managed in one place. An inner component reads the ClientTransport
10
- * from NearestTransportContext and creates the ChatTransport once on first render
11
- * (via useRef).
9
+ * Wraps children with ClientSessionProvider (using UIMessageCodec). The
10
+ * surrounding `<AblyProvider>` supplies the Realtime client; the session
11
+ * resolves the channel from `channelName` itself. An inner component reads
12
+ * the ClientSession via useClientSession() and creates the ChatTransport
13
+ * via useMemo, keyed on the session and transport options.
12
14
  *
13
- * The ChatTransport is NOT closed on unmount — the underlying ClientTransport
14
- * lifecycle is managed by the wrapping TransportProvider. Auto-closing would break
15
- * React Strict Mode, and ChatTransport.close() delegates to ClientTransport.close()
16
- * which TransportProvider already calls.
15
+ * The ChatTransport is NOT closed on unmount — the underlying ClientSession
16
+ * lifecycle is managed by the wrapping ClientSessionProvider. Auto-closing would break
17
+ * React Strict Mode, and ChatTransport.close() delegates to ClientSession.close()
18
+ * which ClientSessionProvider already calls.
17
19
  *
18
20
  * Multiple ChatTransportProviders can be nested using distinct channelNames.
19
- * Each provider merges its transport into the parent registry, so descendants
20
- * can access all registered transports via useChatTransport({ channelName }).
21
+ * Each provider merges its session into the parent registry, so descendants
22
+ * can access all registered sessions via useChatTransport({ channelName }).
21
23
  */
22
24
  import type * as AI from 'ai';
23
- export declare const TransportProvider: import('react').ComponentType<TransportProviderProps<AI.UIMessageChunk, AI.UIMessage<unknown, AI.UIDataTypes, AI.UITools>>>, useAblyMessages: (props?: {
24
- transport?: import('../../../index.js').ClientTransport<AI.UIMessageChunk, AI.UIMessage<unknown, AI.UIDataTypes, AI.UITools>> | undefined;
25
+ export declare const ClientSessionProvider: import('react').ComponentType<ClientSessionProviderProps<VercelInput, VercelOutput, VercelProjection, AI.UIMessage<unknown, AI.UIDataTypes, AI.UITools>>>, useAblyMessages: (props?: {
26
+ session?: import('../../../react/index.js').ClientSession<VercelInput, VercelOutput, VercelProjection, AI.UIMessage<unknown, AI.UIDataTypes, AI.UITools>> | undefined;
25
27
  skip?: boolean;
26
- } | undefined) => import('ably').InboundMessage[], useActiveTurns: (props?: {
27
- transport?: import('../../../index.js').ClientTransport<AI.UIMessageChunk, AI.UIMessage<unknown, AI.UIDataTypes, AI.UITools>> | null | undefined;
28
- } | undefined) => Map<string, Set<string>>, useClientTransport: (props?: {
28
+ } | undefined) => import('ably').InboundMessage[], useClientSession: (props?: {
29
29
  channelName?: string;
30
30
  skip?: boolean;
31
31
  onError?: (error: import('ably').ErrorInfo) => void;
32
- }) => import('../../../react/use-client-transport.js').ClientTransportHandle<AI.UIMessageChunk, AI.UIMessage<unknown, AI.UIDataTypes, AI.UITools>>, useCreateView: (props?: {
33
- transport?: import('../../../index.js').ClientTransport<AI.UIMessageChunk, AI.UIMessage<unknown, AI.UIDataTypes, AI.UITools>> | null | undefined;
32
+ }) => import('../../../react/use-client-session.js').ClientSessionHandle<VercelInput, VercelOutput, VercelProjection, AI.UIMessage<unknown, AI.UIDataTypes, AI.UITools>>, useCreateView: (props?: {
33
+ session?: import('../../../react/index.js').ClientSession<VercelInput, VercelOutput, VercelProjection, AI.UIMessage<unknown, AI.UIDataTypes, AI.UITools>> | null | undefined;
34
34
  limit?: number;
35
35
  skip?: boolean;
36
- } | undefined) => import('../../../react/use-view.js').ViewHandle<AI.UIMessageChunk, AI.UIMessage<unknown, AI.UIDataTypes, AI.UITools>>, useTree: (props?: {
37
- transport?: import('../../../index.js').ClientTransport<AI.UIMessageChunk, AI.UIMessage<unknown, AI.UIDataTypes, AI.UITools>> | undefined;
38
- } | undefined) => import('../../../react/use-tree.js').TreeHandle<AI.UIMessage<unknown, AI.UIDataTypes, AI.UITools>>, useView: (props?: {
39
- transport?: import('../../../index.js').ClientTransport<AI.UIMessageChunk, AI.UIMessage<unknown, AI.UIDataTypes, AI.UITools>> | null | undefined;
40
- view?: import('../../../index.js').View<AI.UIMessageChunk, AI.UIMessage<unknown, AI.UIDataTypes, AI.UITools>> | null | undefined;
36
+ } | undefined) => import('../../../react/use-view.js').ViewHandle<VercelInput, AI.UIMessage<unknown, AI.UIDataTypes, AI.UITools>>, useTree: (props?: {
37
+ session?: import('../../../react/index.js').ClientSession<VercelInput, VercelOutput, VercelProjection, AI.UIMessage<unknown, AI.UIDataTypes, AI.UITools>> | undefined;
38
+ } | undefined) => import('../../../react/use-tree.js').TreeHandle<VercelProjection>, useView: (props?: {
39
+ session?: import('../../../react/index.js').ClientSession<VercelInput, VercelOutput, VercelProjection, AI.UIMessage<unknown, AI.UIDataTypes, AI.UITools>> | null | undefined;
40
+ view?: import('../../../index.js').View<VercelInput, AI.UIMessage<unknown, AI.UIDataTypes, AI.UITools>> | null | undefined;
41
41
  limit?: number;
42
42
  skip?: boolean;
43
- } | undefined) => import('../../../react/use-view.js').ViewHandle<AI.UIMessageChunk, AI.UIMessage<unknown, AI.UIDataTypes, AI.UITools>>;
44
- type CoreTransportProviderProps = Omit<TransportProviderProps<AI.UIMessageChunk, AI.UIMessage>, 'codec' | 'api'> & Partial<Pick<TransportProviderProps<AI.UIMessageChunk, AI.UIMessage>, 'api'>>;
43
+ } | undefined) => import('../../../react/use-view.js').ViewHandle<VercelInput, AI.UIMessage<unknown, AI.UIDataTypes, AI.UITools>>;
44
+ type CoreClientSessionProviderProps = Omit<ClientSessionProviderProps<VercelInput, VercelOutput, VercelProjection, AI.UIMessage>, 'codec'>;
45
45
  /**
46
46
  * Props for {@link ChatTransportProvider}.
47
47
  *
48
- * All {@link TransportProviderProps} for Vercel types except `codec` (baked as UIMessageCodec),
49
- * plus `chatOptions` for customizing chat request construction.
48
+ * All {@link ClientSessionProviderProps} for Vercel types except `codec` (baked as UIMessageCodec),
49
+ * plus the transport-owned invocation POST options (`api` / `credentials` / `fetch`) and
50
+ * `chatOptions` for customizing chat request construction.
50
51
  */
51
- export interface ChatTransportProviderProps extends CoreTransportProviderProps {
52
+ export interface ChatTransportProviderProps extends CoreClientSessionProviderProps {
53
+ /** Endpoint the chat transport POSTs the invocation to, to wake the agent. Default `/api/chat`. */
54
+ api?: string;
55
+ /** Fetch credentials mode for the invocation POST. */
56
+ credentials?: RequestCredentials;
57
+ /** Custom fetch implementation for the invocation POST. Defaults to `globalThis.fetch`. */
58
+ fetch?: typeof globalThis.fetch;
52
59
  /**
53
- * Optional hooks for customizing chat request construction (e.g. prepareSendMessagesRequest).
60
+ * Optional transport options for customizing chat request construction (e.g. the `prepareSendMessagesRequest` hook).
54
61
  * Must be stable across renders — wrap in `useMemo` or define outside the component.
55
62
  * A new object reference triggers ChatTransport recreation.
63
+ * If this object also sets `api`/`credentials`/`fetch`, the dedicated top-level props of the same name take precedence.
56
64
  */
57
65
  chatOptions?: ChatTransportOptions;
58
66
  }
59
67
  /**
60
- * Provide a {@link ChatTransport} and its underlying {@link ClientTransport} to descendant components.
68
+ * Provide a {@link ChatTransport} and its underlying {@link ClientSession} to descendant components.
61
69
  *
62
- * Wraps children with Ably's `ChannelProvider` (via `TransportProvider`) using `channelName`,
63
- * creates a {@link ClientTransport} with UIMessageCodec, wraps it in a {@link ChatTransport},
70
+ * Wraps children with `ClientSessionProvider` using `channelName` (the Realtime
71
+ * client is read from the surrounding `<AblyProvider>`), creates a
72
+ * {@link ClientSession} with UIMessageCodec, wraps it in a {@link ChatTransport},
64
73
  * and registers the full slot in `ChatTransportContext` under `channelName`. Descendants call
65
- * {@link useChatTransport} with the same `channelName` to access both transports.
74
+ * {@link useChatTransport} with the same `channelName` to access both.
66
75
  *
67
- * `useClientTransport` is also available inside this provider's subtree.
76
+ * `useClientSession` is also available inside this provider's subtree.
68
77
  *
69
78
  * ```tsx
70
79
  * <ChatTransportProvider channelName="ai:demo">
@@ -72,13 +81,16 @@ export interface ChatTransportProviderProps extends CoreTransportProviderProps {
72
81
  * </ChatTransportProvider>
73
82
  *
74
83
  * // Inside Chat:
75
- * const { chatTransport, transport } = useChatTransport();
76
- * const { transport } = useClientTransport(); // also available
84
+ * const { chatTransport, session } = useChatTransport();
85
+ * const { session } = useClientSession(); // also available
77
86
  * ```
78
- * @param props - Provider configuration including `channelName`, optional `chatOptions`, and all other transport options.
87
+ * @param props - Provider configuration including `channelName`, the invocation POST options (`api` / `credentials` / `fetch`), optional `chatOptions`, and all other session options.
88
+ * @param props.api - Endpoint the chat transport POSTs the invocation to. Default `/api/chat`.
89
+ * @param props.credentials - Fetch credentials mode for the invocation POST.
90
+ * @param props.fetch - Custom fetch implementation for the invocation POST.
79
91
  * @param props.chatOptions - Optional hooks for customizing chat request construction. Must be stable (memoized) — a new reference recreates the ChatTransport.
80
- * @param props.children - Descendant components that consume the transport via hooks.
81
- * @returns A React element wrapping children with ChannelProvider, TransportContext, and ChatTransportContext.
92
+ * @param props.children - Descendant components that consume the chat transport via hooks.
93
+ * @returns A React element wrapping children with ClientSessionContext and ChatTransportContext.
82
94
  */
83
- export declare const ChatTransportProvider: ({ chatOptions, children, ...transportProps }: ChatTransportProviderProps & PropsWithChildren) => ReactNode;
95
+ export declare const ChatTransportProvider: ({ api, credentials, fetch, chatOptions, children, ...sessionProps }: ChatTransportProviderProps & PropsWithChildren) => ReactNode;
84
96
  export {};
@@ -1,8 +1,7 @@
1
1
  export type { ChatTransport } from '../transport/chat-transport.js';
2
2
  export type { ChatTransportProviderProps } from './contexts/chat-transport-provider.js';
3
- export { ChatTransportProvider, TransportProvider, useAblyMessages, useActiveTurns, useClientTransport, useCreateView, useTree, useView, } from './contexts/chat-transport-provider.js';
3
+ export { ChatTransportProvider, ClientSessionProvider, useAblyMessages, useClientSession, useCreateView, useTree, useView, } from './contexts/chat-transport-provider.js';
4
4
  export type { ChatTransportHandle, UseChatTransportOptions } from './use-chat-transport.js';
5
5
  export { useChatTransport } from './use-chat-transport.js';
6
6
  export type { UseMessageSyncOptions } from './use-message-sync.js';
7
7
  export { useMessageSync } from './use-message-sync.js';
8
- export { useStagedAddToolApprovalResponse } from './use-staged-add-tool-approval-response.js';
@@ -1,16 +1,18 @@
1
- import { ClientTransport } from '../../core/transport/types.js';
1
+ import { ClientSession } from '../../core/transport/types.js';
2
+ import { VercelInput, VercelOutput, VercelProjection } from '../codec/index.js';
2
3
  import { ChatTransport } from '../transport/index.js';
3
4
  /**
4
- * useChatTransport: reads a ChatTransport and its underlying ClientTransport from
5
+ * useChatTransport: reads a ChatTransport and its underlying ClientSession from
5
6
  * the nearest ChatTransportProvider.
6
7
  *
7
- * The transport is created by ChatTransportProvider, which also wraps the subtree
8
- * with TransportProvider and Ably's ChannelProvider. This hook is a thin context
9
- * reader it does not create or manage any transport state.
8
+ * The chat transport is created by ChatTransportProvider, which wraps the subtree
9
+ * with ClientSessionProvider. The Ably Realtime client is read from the
10
+ * surrounding `<AblyProvider>`. This hook is a thin context reader it does
11
+ * not create or manage any session/transport state.
10
12
  *
11
13
  * Pass `channelName` to look up a specific provider by name. Omit to use the nearest
12
14
  * provider in the tree. Pass `skip: true` to defer (e.g. when auth is not yet resolved)
13
- * — returns stub transports whose properties throw with a descriptive error.
15
+ * — returns stubs whose properties throw with a descriptive error.
14
16
  */
15
17
  import * as Ably from 'ably';
16
18
  import type * as AI from 'ai';
@@ -18,53 +20,55 @@ import type * as AI from 'ai';
18
20
  export interface UseChatTransportOptions {
19
21
  /** Channel name to look up; omit to use the nearest {@link ChatTransportProvider}. */
20
22
  channelName?: string;
21
- /** When `true`, return stub transports that throw on any access. */
23
+ /** When `true`, return stubs that throw on any access. */
22
24
  skip?: boolean;
23
25
  }
24
26
  /**
25
27
  * The value returned by {@link useChatTransport}.
26
- * Provides both the underlying {@link ClientTransport} and the {@link ChatTransport}
28
+ * Provides both the underlying {@link ClientSession} and the {@link ChatTransport}
27
29
  * adapter for Vercel's useChat hook.
28
30
  */
29
31
  export interface ChatTransportHandle {
30
32
  /**
31
- * The underlying client transport, also available via {@link useClientTransport}.
32
- * A throwing stub when `skip` is `true`, when no matching {@link TransportProvider}
33
- * was found in the tree, or when transport construction failed. Check `transportError` before use.
33
+ * The underlying client session, also available via {@link useClientSession}.
34
+ * A throwing stub when `skip` is `true`, when no matching {@link ClientSessionProvider}
35
+ * was found in the tree, or when session construction failed. Check `sessionError` before use.
34
36
  */
35
- transport: ClientTransport<AI.UIMessageChunk, AI.UIMessage>;
37
+ session: ClientSession<VercelInput, VercelOutput, VercelProjection, AI.UIMessage>;
36
38
  /**
37
39
  * The chat transport adapter for use with Vercel's `useChat` hook.
38
40
  *
39
- * A throwing stub when `skip` is `true`, when no matching
40
- * {@link ChatTransportProvider} was found in the tree, or when the underlying
41
- * {@link ClientTransport} construction failed. Check both `chatTransportError`
42
- * and `transportError` before use.
41
+ * A throwing stub when `skip` is `true` or when no matching
42
+ * {@link ChatTransportProvider} was found in the tree. When a provider is found
43
+ * but the underlying {@link ClientSession} failed to construct, this is the real
44
+ * transport and `sessionError` is set instead. Check `chatTransportError` and
45
+ * `sessionError` before use.
43
46
  */
44
47
  chatTransport: ChatTransport;
45
48
  /**
46
- * Set when no matching {@link TransportProvider} was found, when transport
49
+ * Set when no matching {@link ClientSessionProvider} was found, when session
47
50
  * construction failed, and `skip` is `false`.
48
- * `undefined` when the transport resolved successfully or when `skip` is `true`.
51
+ * `undefined` when the session resolved successfully or when `skip` is `true`.
49
52
  */
50
- transportError?: Ably.ErrorInfo | undefined;
53
+ sessionError?: Ably.ErrorInfo | undefined;
51
54
  /**
52
- * Set when no matching {@link ChatTransportProvider} was found or when transport
53
- * construction failed, and `skip` is `false`.
54
- * `undefined` when the transport resolved successfully or when `skip` is `true`.
55
+ * Set only when no matching {@link ChatTransportProvider} was found and `skip` is
56
+ * `false`.
57
+ * `undefined` when the chat transport resolved successfully (even if session
58
+ * construction failed — see `sessionError`) or when `skip` is `true`.
55
59
  */
56
60
  chatTransportError?: Ably.ErrorInfo | undefined;
57
61
  }
58
62
  /**
59
- * Access a {@link ChatTransport} and {@link ClientTransport} from the nearest {@link ChatTransportProvider}.
63
+ * Access a {@link ChatTransport} and {@link ClientSession} from the nearest {@link ChatTransportProvider}.
60
64
  *
61
65
  * When `channelName` is omitted, the innermost `ChatTransportProvider` in the tree is used.
62
- * When `skip` is `true`, returns stub transports whose every property and method throws
66
+ * When `skip` is `true`, returns stubs whose every property and method throws
63
67
  * an {@link Ably.ErrorInfo} — safe to hold in state before conditions are ready.
64
68
  * When no provider is found, returns stubs with `chatTransportError` set instead of throwing.
65
- * @param props - Options for selecting the transport.
69
+ * @param props - Options for selecting the chat transport.
66
70
  * @param props.channelName - The channel name passed to the enclosing `ChatTransportProvider`. Omit to use the nearest.
67
71
  * @param props.skip - When `true`, return stubs that throw on any access instead of reading from context.
68
- * @returns The `ChatTransportHandle` containing both the chat transport adapter and the underlying client transport.
72
+ * @returns The `ChatTransportHandle` containing both the chat transport adapter and the underlying client session.
69
73
  */
70
74
  export declare const useChatTransport: ({ channelName, skip }?: UseChatTransportOptions) => ChatTransportHandle;
@@ -1,51 +1,38 @@
1
1
  /**
2
- * useMessageSync: wires transport message lifecycle events into useChat's setMessages.
2
+ * useMessageSync: wire view updates into useChat's setMessages.
3
3
  *
4
- * Subscribes to the transport view's 'update' event and replaces messages state
5
- * with the view's authoritative message list.
4
+ * During active own-run streams, setMessages is gated to avoid an
5
+ * ID-mismatch in useChat's write(). When the stream ends, the gate
6
+ * opens and the view is synced into useChat's overlay.
6
7
  *
7
- * When a ChatTransport is provided (resolved from the nearest ChatTransportProvider),
8
- * setMessages calls are gated during active own-turn streams. This prevents the
9
- * push/replace ID mismatch in useChat's write() function. When the stream finishes,
10
- * the gate opens and an immediate sync fires to pick up any observer messages that
11
- * arrived during the stream.
12
- *
13
- * All dependencies are resolved from the nearest ChatTransportProvider via
14
- * useChatTransport(). Pass channelName to select a specific provider; omit to use
15
- * the nearest. Pass skip: true to pause all subscriptions.
16
- *
17
- * Returns the unsubscribe function in the useEffect cleanup so handlers
18
- * are removed on unmount or when dependencies change.
8
+ * The sync is a per-message merge, not a replace: when the overlay has
9
+ * resolved a client-side tool locally (via addToolResult) but the
10
+ * tree's echo hasn't landed yet, the overlay's resolution wins.
11
+ * Without that, the gate-open sync would race the AI SDK's post-stream
12
+ * sendAutomaticallyWhen check and could clobber the resolution before
13
+ * the continuation publishes.
19
14
  */
20
15
  import type * as AI from 'ai';
21
16
  /** Options for {@link useMessageSync}. */
22
17
  export interface UseMessageSyncOptions {
23
18
  /**
24
- * The `setMessages` updater function from `useChat()`. Required.
25
- * Called with a function that replaces the previous message list with the
26
- * transport's current authoritative message list.
19
+ * The `setMessages` updater function from `useChat()`. Called with an
20
+ * updater that returns the next overlay.
27
21
  */
28
22
  setMessages: (updater: (prev: AI.UIMessage[]) => AI.UIMessage[]) => void;
29
23
  /**
30
24
  * Channel name of the {@link ChatTransportProvider} to observe.
31
- * Omit to use the nearest provider in the tree.
25
+ * Omit to use the nearest provider.
32
26
  */
33
27
  channelName?: string;
34
- /**
35
- * When `true`, skip all subscriptions and do nothing.
36
- * Use when the hook's dependencies are not yet resolved (e.g. auth pending).
37
- */
28
+ /** When `true`, skip all subscriptions. */
38
29
  skip?: boolean;
39
30
  }
40
31
  /**
41
- * Wire transport message updates into `useChat()`'s `setMessages` updater.
42
- *
43
- * Resolves both the transport view and the streaming gate from the nearest
44
- * `ChatTransportProvider`. Pass `channelName` to target a specific provider.
45
- * Pass `skip: true` to pause all subscriptions.
32
+ * Subscribe to view updates and sync them into `useChat()`'s overlay.
46
33
  * @param options - Hook options.
47
- * @param options.setMessages - The `setMessages` function from `useChat()`. Required.
48
- * @param options.channelName - Channel name of the provider to observe; defaults to nearest.
34
+ * @param options.setMessages - The `setMessages` function from `useChat()`.
35
+ * @param options.channelName - Channel name of the provider to observe; defaults to the nearest.
49
36
  * @param options.skip - When `true`, skip all subscriptions.
50
37
  */
51
38
  export declare const useMessageSync: ({ setMessages, channelName, skip }: UseMessageSyncOptions) => void;
@@ -0,0 +1,29 @@
1
+ import { RunEndReason, StreamResult } from '../core/transport/types.js';
2
+ import type * as AI from 'ai';
3
+ /**
4
+ * Derive the outcome for a Vercel `streamText` response that was piped through
5
+ * `Run.pipe`: either a terminal {@link RunEndReason} the caller passes to
6
+ * `Run.end`, or the sentinel `'suspend'` telling the caller to call
7
+ * `Run.suspend` instead. Preserves transport-level outcomes (`'cancelled'`,
8
+ * `'error'`) from the pipe result; when the pipe completed naturally, awaits
9
+ * Vercel's `finishReason` and returns `'suspend'` for `'tool-calls'` (the LLM
10
+ * requested tools the SDK did not auto-execute, so the run should suspend
11
+ * rather than end), or `'complete'` otherwise.
12
+ *
13
+ * Tolerates `finishReason` rejection. Vercel AI SDK v6 rejects
14
+ * `streamText().finishReason` with the abort signal's reason when the stream
15
+ * is aborted before any step completes, and rejects with
16
+ * `NoOutputGeneratedError` when the model produced nothing at all. Without
17
+ * this guard the rejection would bubble out of the route handler's `after()`
18
+ * block, skip the developer's `Run.end(...)` call, and leave the run with no
19
+ * `ai-run-end` event on the channel — so observers' UIs stay stuck on
20
+ * `streaming` indefinitely.
21
+ *
22
+ * Saves callers from interpreting Vercel domain semantics inline at the end
23
+ * of every route handler.
24
+ * @param pipeResult - The result returned by `Run.pipe`.
25
+ * @param finishReason - The `finishReason` promise from a `streamText` result.
26
+ * @returns `'suspend'` when the run should suspend awaiting tool input, or the
27
+ * {@link RunEndReason} to pass to `Run.end` otherwise.
28
+ */
29
+ export declare const vercelRunOutcome: (pipeResult: StreamResult, finishReason: PromiseLike<AI.FinishReason>) => Promise<RunEndReason | "suspend">;
@@ -1,11 +1,12 @@
1
- import { ClientTransport, CloseOptions } from '../../core/transport/types.js';
1
+ import { ClientSession } from '../../core/transport/types.js';
2
+ import { VercelInput, VercelOutput, VercelProjection } from '../codec/index.js';
2
3
  /**
3
- * Vercel chat transport: wraps a core ClientTransport to satisfy the
4
+ * Vercel chat transport: wraps a core ClientSession to satisfy the
4
5
  * ChatTransport interface that useChat expects.
5
6
  *
6
- * This is a thin adapter — the real logic lives in the core transport.
7
+ * This is a thin adapter — the real logic lives in the core client session.
7
8
  * The chat transport maps Vercel's sendMessages/reconnectToStream contract
8
- * to the core transport's send/cancel methods.
9
+ * to the core session's send/cancel methods.
9
10
  *
10
11
  * useChat manages message state before calling sendMessages:
11
12
  * - submit-message (new): appends the new user message, passes the full array
@@ -13,13 +14,20 @@ import { ClientTransport, CloseOptions } from '../../core/transport/types.js';
13
14
  * passes the truncated array with messageId set
14
15
  * - regenerate-message: truncates after the target, passes the truncated array
15
16
  *
16
- * The adapter uses `trigger` to determine the history/messages split:
17
- * - submit-message: last message is new (publish to channel), rest is history
17
+ * The adapter uses `(trigger, last-message role)` to determine the
18
+ * history/messages split:
19
+ * - submit-message + last message is a user message: that last message is new
20
+ * (publish to channel), rest is history. A new submit and an edit both take
21
+ * this path — an edit just carries a messageId.
22
+ * - submit-message + last message is an assistant already in the tree
23
+ * (continuation): no new messages, entire array is history
18
24
  * - regenerate-message: no new messages, entire array is history
19
25
  *
20
- * When messageId is set (edit or regeneration), the adapter computes fork
21
- * metadata (forkOf/parent) from the conversation tree so the server can
22
- * place the response on the correct branch.
26
+ * For an edit (submit-message with messageId) and for forking off an
27
+ * unresolved tool call, the adapter computes fork metadata (forkOf/parent)
28
+ * from the conversation tree so the server can place the response on the
29
+ * correct branch. Regeneration fork metadata is NOT computed here —
30
+ * `View.regenerate` derives forkOf/parent from the tree itself.
23
31
  */
24
32
  import type * as AI from 'ai';
25
33
  /**
@@ -40,23 +48,34 @@ export interface SendMessagesRequestContext {
40
48
  messageId?: string;
41
49
  /** Previous messages in the conversation (context for the LLM). */
42
50
  history: AI.UIMessage[];
43
- /** The new message(s) being sent (to publish to the channel). Empty for regeneration. */
51
+ /** The new message(s) being sent (to publish to the channel). Empty for regeneration and for continuations (an auto-submit where the last message is an already-tracked assistant). */
44
52
  messages: AI.UIMessage[];
45
- /** The msg-id of the message being forked (regenerated or edited). */
53
+ /** The codec-message-id of the message being forked the edited user message, or the preceding assistant when forking off an unresolved tool call. Undefined for regeneration (View.regenerate derives it) and fresh sends. */
46
54
  forkOf?: string;
47
- /** The msg-id of the predecessor in the conversation thread. */
55
+ /** The codec-message-id of the predecessor in the conversation thread. */
48
56
  parent?: string;
49
57
  }
58
+ /** Default agent endpoint the transport POSTs invocations to — mirrors Vercel's DefaultChatTransport. */
59
+ export declare const DEFAULT_VERCEL_API = "/api/chat";
50
60
  /** Options for customizing the ChatTransport behavior. */
51
61
  export interface ChatTransportOptions {
52
62
  /**
53
- * Customize the POST body before sending. Called by sendMessages()
54
- * with the conversation context. Return the body and headers for
55
- * the HTTP POST.
56
- *
57
- * Default: sends all previous messages as `history` in the body.
63
+ * Endpoint the transport POSTs the invocation pointer to, to wake the
64
+ * agent. Mirrors useChat's request-driven contract. Default `/api/chat`.
65
+ */
66
+ api?: string;
67
+ /** Fetch credentials mode for the invocation POST (e.g. `'include'`). */
68
+ credentials?: RequestCredentials;
69
+ /** Custom fetch implementation for the invocation POST. Defaults to `globalThis.fetch`. */
70
+ fetch?: typeof globalThis.fetch;
71
+ /**
72
+ * Customize the invocation POST before sending. Called by sendMessages()
73
+ * with the conversation context; the returned `body` is merged into the
74
+ * POST body (the run's invocation identifiers always take precedence) and
75
+ * `headers` are added to the request. Use it for auth headers or extra
76
+ * agent metadata.
58
77
  * @param context - The conversation context for the current request.
59
- * @returns The body and headers to use for the HTTP POST.
78
+ * @returns The body and headers to merge into the invocation POST.
60
79
  */
61
80
  prepareSendMessagesRequest?: (context: SendMessagesRequestContext) => {
62
81
  body?: Record<string, unknown>;
@@ -109,8 +128,8 @@ export interface ChatTransport {
109
128
  chatId: string;
110
129
  } & ChatRequestOptions) => Promise<ReadableStream<AI.UIMessageChunk> | null>;
111
130
  /** Close the underlying transport, releasing all resources. */
112
- close(options?: CloseOptions): Promise<void>;
113
- /** Whether an own-turn stream is currently being consumed by useChat. */
131
+ close(): Promise<void>;
132
+ /** Whether an own-run stream is currently being consumed by useChat. */
114
133
  readonly streaming: boolean;
115
134
  /**
116
135
  * Subscribe to streaming state changes. The callback fires when the
@@ -122,19 +141,19 @@ export interface ChatTransport {
122
141
  onStreamingChange(callback: (streaming: boolean) => void): () => void;
123
142
  }
124
143
  /**
125
- * Create a Vercel ChatTransport from a core ClientTransport.
144
+ * Create a Vercel ChatTransport from a core ClientSession.
126
145
  *
127
146
  * Exposes a `streaming` flag and `onStreamingChange` callback so that
128
- * `useMessageSync` can gate `setMessages` calls during active own-turn
147
+ * `useMessageSync` can gate `setMessages` calls during active own-run
129
148
  * streams, preventing the push/replace ID mismatch in useChat's `write()`.
130
149
  *
131
150
  * Note: concurrent `sendMessage` calls from the same user are a useChat
132
151
  * limitation that cannot be fixed from the transport layer. The
133
152
  * developer must respect useChat's `status` and only call `sendMessage`
134
153
  * when status is `'ready'`.
135
- * @param transport - The core client transport to wrap.
154
+ * @param session - The core client session to wrap.
136
155
  * @param chatOptions - Optional hooks for customizing request construction.
137
156
  * @returns A {@link ChatTransport} compatible with Vercel's useChat hook.
138
157
  */
139
- export declare const createChatTransport: (transport: ClientTransport<AI.UIMessageChunk, AI.UIMessage>, chatOptions?: ChatTransportOptions) => ChatTransport;
158
+ export declare const createChatTransport: (session: ClientSession<VercelInput, VercelOutput, VercelProjection, AI.UIMessage>, chatOptions?: ChatTransportOptions) => ChatTransport;
140
159
  export {};
@@ -1,4 +1,5 @@
1
- import { ClientTransport, ClientTransportOptions, ServerTransport, ServerTransportOptions } from '../../core/transport/types.js';
1
+ import { AgentSession, AgentSessionOptions, ClientSession, ClientSessionOptions } from '../../core/transport/types.js';
2
+ import { VercelInput, VercelOutput, VercelProjection } from '../codec/index.js';
2
3
  /**
3
4
  * Vercel AI SDK transport wrappers that pre-bind the UIMessageCodec.
4
5
  *
@@ -6,34 +7,37 @@ import { ClientTransport, ClientTransportOptions, ServerTransport, ServerTranspo
6
7
  * explicitly when using the Vercel AI SDK integration.
7
8
  *
8
9
  * ```ts
9
- * import { createClientTransport } from '@ably/ai-transport/vercel';
10
+ * import { createClientSession } from '@ably/ai-transport/vercel';
10
11
  *
11
- * const transport = createClientTransport({ channel });
12
+ * const session = createClientSession({ client, channelName: 'ai:demo' });
13
+ * await session.connect();
12
14
  * ```
13
15
  */
14
16
  export type { ChatTransport, ChatTransportOptions, SendMessagesRequestContext } from './chat-transport.js';
15
- export { createChatTransport } from './chat-transport.js';
17
+ export { createChatTransport, DEFAULT_VERCEL_API } from './chat-transport.js';
16
18
  import type * as AI from 'ai';
17
- /** Core client transport options with Vercel AI SDK types pre-applied. */
18
- type CoreClientOpts = ClientTransportOptions<AI.UIMessageChunk, AI.UIMessage>;
19
- /** Options for creating a Vercel client transport. Same as core options but without the codec field, and with `api` optional (defaults to `"/api/chat"`). */
20
- export type VercelClientTransportOptions = Omit<CoreClientOpts, 'codec' | 'api'> & Partial<Pick<CoreClientOpts, 'api'>>;
21
- /** Options for creating a Vercel server transport. Same as core options but without the codec field. */
22
- export type VercelServerTransportOptions = Omit<ServerTransportOptions<AI.UIMessageChunk, AI.UIMessage>, 'codec'>;
23
- export declare const DEFAULT_VERCEL_API = "/api/chat";
19
+ /** Core client session options with Vercel AI SDK types pre-applied. */
20
+ type CoreClientOpts = ClientSessionOptions<VercelInput, VercelOutput, VercelProjection, AI.UIMessage>;
21
+ /** Options for creating a Vercel client session. Same as core options but without the codec field. */
22
+ export type VercelClientSessionOptions = Omit<CoreClientOpts, 'codec'>;
23
+ /** Options for creating a Vercel agent session. Same as core options but without the codec field. */
24
+ export type VercelAgentSessionOptions = Omit<AgentSessionOptions<VercelInput, VercelOutput, VercelProjection, AI.UIMessage>, 'codec'>;
24
25
  /**
25
- * Create a client-side transport pre-configured with the Vercel AI SDK codec.
26
+ * Create a client-side session pre-configured with the Vercel AI SDK codec.
26
27
  *
27
- * Equivalent to calling the core `createClientTransport` with `codec: UIMessageCodec`.
28
- * @param options - Configuration for the client transport (codec is provided automatically).
29
- * @returns A new {@link ClientTransport} for Vercel AI SDK UIMessage/UIMessageChunk types.
28
+ * Equivalent to calling the core `createClientSession` with `codec: UIMessageCodec`.
29
+ * The core session is a pure Ably-channel transport it never sends HTTP.
30
+ * To wake a serverless agent over HTTP, POST `run.toInvocation().toJSON()`
31
+ * yourself, or use `createChatTransport` (which does it for useChat parity).
32
+ * @param options - Configuration for the client session (codec is provided automatically).
33
+ * @returns A new {@link ClientSession} for Vercel AI SDK UIMessage/UIMessageChunk types.
30
34
  */
31
- export declare const createClientTransport: (options: VercelClientTransportOptions) => ClientTransport<AI.UIMessageChunk, AI.UIMessage>;
35
+ export declare const createClientSession: (options: VercelClientSessionOptions) => ClientSession<VercelInput, VercelOutput, VercelProjection, AI.UIMessage>;
32
36
  /**
33
- * Create a server-side transport pre-configured with the Vercel AI SDK codec.
37
+ * Create an agent (server-side) session pre-configured with the Vercel AI SDK codec.
34
38
  *
35
- * Equivalent to calling the core `createServerTransport` with `codec: UIMessageCodec`.
36
- * @param options - Configuration for the server transport (codec is provided automatically).
37
- * @returns A new {@link ServerTransport} for Vercel AI SDK UIMessage/UIMessageChunk types.
39
+ * Equivalent to calling the core `createAgentSession` with `codec: UIMessageCodec`.
40
+ * @param options - Configuration for the agent session (codec is provided automatically).
41
+ * @returns A new {@link AgentSession} for Vercel AI SDK UIMessage/UIMessageChunk types.
38
42
  */
39
- export declare const createServerTransport: (options: VercelServerTransportOptions) => ServerTransport<AI.UIMessageChunk, AI.UIMessage>;
43
+ export declare const createAgentSession: (options: VercelAgentSessionOptions) => AgentSession<VercelOutput, VercelProjection, AI.UIMessage>;