-
Notifications
You must be signed in to change notification settings - Fork 61
Closed
Description
Problem Description
AI message streaming using @convex-dev/agent does not work on React Native Expo app. Messages appear all at once after AI completes generation instead of streaming incrementally character-by-character.
Environment
- Platform: React Native 0.76.9 (Expo ~52.0.46)
- Convex Version:
^1.25.2 - Convex Agent Version:
@convex-dev/agent ^0.2.10 - Metro Config: Added
unstable_enablePackageExports: truefor package.json exports resolution - Import Path: Using
@convex-dev/agent/react(not/dist/react) - Backend: Correctly configured with
saveStreamDeltas: trueandsyncStreams() - Other Clients: Web client using identical Convex backend works perfectly with streaming
Expected Behavior
- Message status should transition:
"pending"→"streaming"→"success" useThreadMessagesshould receive streaming deltas fromuseStreamingThreadMessages- Text should appear incrementally as AI generates response
useSmoothTextshould animate text appearance character-by-character
Actual Behavior
- Message status jumps directly:
"pending"→"success"(never shows"streaming") - All messages have
streaming: falsefield - Complete text appears instantly when AI finishes generating (no incremental updates)
messagesobject contains only["results", "status", "isLoading", "loadMore"]keys - no streaming data
Diagnostic Logging Results
// What we observe:
[STREAM-CHECK] {
resultsCount: 2,
status: "success",
streamEnabled: true,
messageKeys: ["results", "status", "isLoading", "loadMore"],
hasStreamsProperty: false,
streamsValue: undefined,
last3Messages: [
{ order: 1, streaming: false, status: "success" },
{ order: 2, streaming: false, status: "success" }
]
}
// Status progression observed:
[MSG-STATUS] { role: "assistant", status: "pending", textLen: 0 }
[MSG-STATUS] { role: "assistant", status: "success", textLen: 266 } // Full text arrives instantlyKey observation: streaming: false on ALL messages, and no streams property in the returned object from useThreadMessages.
Backend Configuration (Verified Working on Web)
// Backend saves deltas:
export const generateResponse = internalActionWithUser({
handler: async (ctx, args) => {
const result = await thread.streamText(
{ system: systemPrompt, messages: [toolMessage], tools },
{
saveStreamDeltas: true, // ✓ Enabled
contextOptions: { recentMessages: 20 }
}
);
await result.consumeStream();
},
});
// Backend returns streams:
export const listThreadMessages = authorizedQuery({
args: {
threadId: z.string(),
paginationOpts: convexToZod(paginationOptsValidator),
streamArgs: convexToZod(vStreamArgs), // ✓ Accepts stream args
},
handler: async (ctx, { threadId, paginationOpts, streamArgs }) => {
const paginated = await chatAgent.listMessages(ctx, { threadId, paginationOpts });
const streams = await chatAgent.syncStreams(ctx, { threadId, streamArgs }); // ✓ Syncs streams
return { ...paginated, streams }; // ✓ Returns streams
},
});Client Usage
const messages = useThreadMessages(
api.app.chat.listThreadMessages,
selectedThreadId ? { threadId: selectedThreadId } : "skip",
{
initialNumItems: 50,
stream: true, // ✓ Streaming enabled
}
);
const uiMessages = toUIMessages(messages.results ?? []);// components/AI/components/MessageBubble.tsx
const [visibleText, smooth] = useSmoothText(text, {
startStreaming: status === "streaming", // Never true on React Native
});Comparison: Web vs React Native
Web Client (Working):
- Uses identical backend queries
- Same
useThreadMessageshook pattern - Streaming works correctly
- Status shows
"streaming"during generation - Text appears incrementally
React Native Client (Broken):
- Uses identical backend queries
- Same
useThreadMessageshook pattern - Streaming does NOT work
- Status jumps from
"pending"to"success" - Text appears all at once when complete
Question
Is there a known React Native-specific limitation or configuration required for useThreadMessages streaming that differs from web? The fact that the web client works perfectly with the same backend suggests a client-side React Native issue.
Specifically:
- Does
useStreamingThreadMessageswork correctly on React Native? - Are there any React Native-specific subscription/polling behaviors that might cause delayed delta arrival?
- Could there be a timing issue where deltas arrive after the message completes?
Metadata
Metadata
Assignees
Labels
No labels