Skip to content

Commit b90410f

Browse files
committed
react: update hooks to support context-based transport fallback
- Updated hooks (`useView`, `useTree`, `useCreateView`, `useAblyMessages`, `useActiveTurns`, etc.) to use nearest transport for transport fallback when no explicit transport is provided. - Modified `TransportProvider` - Adjusted all affected hooks and types to align with the updated transport resolution mechanism via context.
1 parent 87de56b commit b90410f

23 files changed

Lines changed: 698 additions & 323 deletions

README.md

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -144,12 +144,17 @@ export async function POST(req: Request) {
144144

145145
import { useChat } from '@ai-sdk/react';
146146
import type * as AI from 'ai';
147-
import { TransportProvider, useClientTransport, useActiveTurns, useView } from '@ably/ai-transport/react';
147+
import { createTransportHooks } from '@ably/ai-transport/react';
148148
import { useChatTransport, useMessageSync } from '@ably/ai-transport/vercel/react';
149149
import { UIMessageCodec } from '@ably/ai-transport/vercel';
150150

151+
const { TransportProvider, useClientTransport, useActiveTurns, useView } = createTransportHooks<
152+
AI.UIMessageChunk,
153+
AI.UIMessage
154+
>();
155+
151156
function ChatInner({ chatId }: { chatId: string }) {
152-
const transport = useClientTransport<AI.UIMessageChunk, AI.UIMessage>();
157+
const transport = useClientTransport();
153158
const chatTransport = useChatTransport(transport);
154159

155160
const { messages, setMessages, sendMessage, stop } = useChat({
@@ -159,8 +164,8 @@ function ChatInner({ chatId }: { chatId: string }) {
159164

160165
useMessageSync(transport, setMessages);
161166

162-
const activeTurns = useActiveTurns(transport);
163-
useView(transport, { limit: 30 });
167+
const activeTurns = useActiveTurns();
168+
useView({ limit: 30 });
164169

165170
return (
166171
<div>
@@ -174,7 +179,12 @@ function ChatInner({ chatId }: { chatId: string }) {
174179
}}
175180
>
176181
{activeTurns.size > 0 ? (
177-
<button type="button" onClick={stop}>Stop</button>
182+
<button
183+
type="button"
184+
onClick={stop}
185+
>
186+
Stop
187+
</button>
178188
) : (
179189
<button type="submit">Send</button>
180190
)}
@@ -185,7 +195,11 @@ function ChatInner({ chatId }: { chatId: string }) {
185195

186196
function Chat({ chatId, clientId }: { chatId: string; clientId?: string }) {
187197
return (
188-
<TransportProvider channelName={chatId} codec={UIMessageCodec} clientId={clientId}>
198+
<TransportProvider
199+
channelName={chatId}
200+
codec={UIMessageCodec}
201+
clientId={clientId}
202+
>
189203
<ChatInner chatId={chatId} />
190204
</TransportProvider>
191205
);

demo/vercel/react/use-chat/src/app/chat.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import { useClientTools } from './hooks/use-client-tools';
1515

1616
export function Chat({ chatId, clientId, historyLimit }: { chatId: string; clientId?: string; historyLimit?: number }) {
1717
// Transport is created by TransportProvider in page.tsx
18-
const transport = useClientTransport<AI.UIMessageChunk, AI.UIMessage>();
18+
const transport = useClientTransport<AI.UIMessageChunk, AI.UIMessage>({ channelName: chatId });
1919
const chatTransport = useChatTransport(transport);
2020

2121
const {
@@ -33,15 +33,15 @@ export function Chat({ chatId, clientId, historyLimit }: { chatId: string; clien
3333

3434
useMessageSync(transport, setMessages);
3535

36-
const activeTurns = useActiveTurns(transport);
36+
const activeTurns = useActiveTurns({ transport });
3737
const hasAnyTurns = activeTurns.size > 0;
3838

39-
// Auto-loads first page on mount (options provided = enabled)
40-
const { nodes, hasOlder, loading, loadOlder } = useView(transport, { limit: historyLimit ?? 30 });
39+
// Auto-loads first page on mount
40+
const { nodes, hasOlder, loading, loadOlder } = useView({ transport, limit: historyLimit ?? 30 });
4141

4242
useClientTools(chatMessages, addToolResult, nodes, clientId);
4343

44-
const ablyMessages = useAblyMessages(transport);
44+
const ablyMessages = useAblyMessages({ transport });
4545

4646
return (
4747
<div className="flex h-dvh">

demo/vercel/react/use-client-transport/src/app/components/chat.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,17 +30,17 @@ interface ChatProps {
3030

3131
export function Chat({ chatId, clientId, historyLimit }: ChatProps) {
3232
// Transport is created by TransportProvider in page.tsx
33-
const transport = useClientTransport<AI.UIMessageChunk, AI.UIMessage>(chatId);
33+
const transport = useClientTransport<AI.UIMessageChunk, AI.UIMessage>({ channelName: chatId });
3434
const [split, setSplit] = useState(false);
3535

3636
const limit = historyLimit ?? 30;
37-
const view = useView(transport, { limit });
38-
const splitView = useCreateView(split ? transport : undefined, { limit });
37+
const view = useView({ transport, limit });
38+
const splitView = useCreateView({ transport, limit, skip: !split });
3939

4040
useClientTools(view, clientId);
4141

42-
const activeTurns = useActiveTurns(transport);
43-
const ablyMessages = useAblyMessages(transport);
42+
const activeTurns = useActiveTurns({ transport });
43+
const ablyMessages = useAblyMessages({ transport });
4444
const queue = useMessageQueue(transport, view.send);
4545

4646
const handleToolApproved = useCallback(

docs/frameworks/vercel-ai-sdk.md

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,13 @@ import { useChat } from '@ai-sdk/react';
2727
import type * as AI from 'ai';
2828

2929
// Wrap your component tree with TransportProvider
30-
<TransportProvider channelName={chatId} codec={UIMessageCodec} clientId={clientId}>
30+
<TransportProvider
31+
channelName={chatId}
32+
codec={UIMessageCodec}
33+
clientId={clientId}
34+
>
3135
<ChatInner chatId={chatId} />
32-
</TransportProvider>
36+
</TransportProvider>;
3337

3438
// Inside ChatInner:
3539
const transport = useClientTransport<AI.UIMessageChunk, AI.UIMessage>();
@@ -51,18 +55,18 @@ useMessageSync(transport, setMessages);
5155
Use the generic React hooks directly. You manage message state through the transport's conversation tree instead of `useChat()`.
5256

5357
```tsx
54-
import {
55-
TransportProvider,
56-
useClientTransport,
57-
useView,
58-
useActiveTurns} from '@ably/ai-transport/react';
58+
import { TransportProvider, useClientTransport, useView, useActiveTurns } from '@ably/ai-transport/react';
5959
import { UIMessageCodec } from '@ably/ai-transport/vercel';
6060
import type * as AI from 'ai';
6161

6262
// Wrap your component tree with TransportProvider
63-
<TransportProvider channelName={chatId} codec={UIMessageCodec} clientId={clientId}>
63+
<TransportProvider
64+
channelName={chatId}
65+
codec={UIMessageCodec}
66+
clientId={clientId}
67+
>
6468
<ChatInner />
65-
</TransportProvider>
69+
</TransportProvider>;
6670

6771
// Inside ChatInner:
6872
const transport = useClientTransport<AI.UIMessageChunk, AI.UIMessage>();

0 commit comments

Comments
 (0)