From ab4b8829bbff6b7a159e68a591532cef0375e474 Mon Sep 17 00:00:00 2001 From: snehasishcodes <–snehasish.ray2025@iem.edu.in> Date: Sun, 18 Oct 2026 23:51:20 +0530 Subject: [PATCH] fix(mobile): resolve reconnect status, role switching, message status, and navigation bugs --- .../project/[projectId]/[sessionId]/index.tsx | 16 ++++++++++++-- apps/mobile/components/hooks/event-stream.ts | 22 ++++++++++++++++--- apps/mobile/components/session-header.tsx | 2 +- 3 files changed, 34 insertions(+), 6 deletions(-) diff --git a/apps/mobile/app/project/[projectId]/[sessionId]/index.tsx b/apps/mobile/app/project/[projectId]/[sessionId]/index.tsx index b02c4e2..a6472eb 100644 --- a/apps/mobile/app/project/[projectId]/[sessionId]/index.tsx +++ b/apps/mobile/app/project/[projectId]/[sessionId]/index.tsx @@ -933,7 +933,9 @@ function SessionScreenInner({ projectId, sessionId }: { projectId: string; sessi if (assistantMsgs.length === 0) { const startAt = sorted[lastUserIdx].time?.created ?? null - return startAt == null ? null : { startAt, endAt: null as number | null, agent: optimisticAgent } + if (startAt == null) return null + const isOptimistic = lastUser.id.startsWith("local-") + return { startAt, endAt: null as number | null, agent: optimisticAgent, isSending: isOptimistic } } const startAt = assistantMsgs[0].time?.created ?? null @@ -955,12 +957,22 @@ function SessionScreenInner({ projectId, sessionId }: { projectId: string; sessi // The list is inverted, so the header renders visually below the newest message const StreamingIndicator = useMemo(() => { if (!turn || turn.startAt == null) return null + if (turn.isSending) { + return ( + + + + Sending message... + + + ) + } return ( ) - }, [turn]) + }, [turn, theme]) const ListFooterComponent = useMemo(() => { if (!isLoadingMore) return null diff --git a/apps/mobile/components/hooks/event-stream.ts b/apps/mobile/components/hooks/event-stream.ts index 2516cbf..9fd5560 100644 --- a/apps/mobile/components/hooks/event-stream.ts +++ b/apps/mobile/components/hooks/event-stream.ts @@ -350,6 +350,19 @@ export function useEventStream(url?: string, sessionId?: string, token?: string, } const msg = existing[msgIdx] + if (msg.role === "user") { + existing.push({ + id: messageID, + sessionID: currentSessionId, + role: "assistant", + time: { created: Date.now() }, + agent: "build", + model: { providerID: "...", modelID: "..." }, + parts: [{ id: partID, type: "text", text: delta } as Part], + } as unknown as Message) + scheduleFlush() + break + } const parts = msg.parts ?? [] const partIdx = parts.findIndex(p => p.id === partID) if (partIdx >= 0) { @@ -375,16 +388,15 @@ export function useEventStream(url?: string, sessionId?: string, token?: string, let msgIdx = existing.findIndex(m => m.id === part.messageID) if (msgIdx < 0) { - // Part arrived before its message (common for user file parts). - // Create a placeholder instead of dropping it. let incoming = part as Part if (incoming.type === "file" && localFileUriBackup.length > 0) { incoming = { ...incoming, url: localFileUriBackup.shift()! } as Part } + const partRole = incoming.type === "text" ? "assistant" : "user" existing.push({ id: part.messageID, sessionID: currentSessionId, - role: "user", + role: partRole, time: { created: Date.now() }, agent: "build", model: { providerID: "...", modelID: "..." }, @@ -643,7 +655,11 @@ export function useEventStream(url?: string, sessionId?: string, token?: string, reconnectAttempts++ const delay = reconnectDelays[Math.min(reconnectAttempts - 1, reconnectDelays.length - 1)] + // Only show reconnecting/connectivity-issues after repeated failures + // to avoid banner flicker on brief, self-healing stream drops if (reconnectAttempts <= 2) { + // Keep "connected" — the stream may recover on its own + } else if (reconnectAttempts <= 4) { setConnectionStatus("reconnecting") } else { setConnectionStatus("connectivity-issues") diff --git a/apps/mobile/components/session-header.tsx b/apps/mobile/components/session-header.tsx index 3b05b39..f39b1a9 100644 --- a/apps/mobile/components/session-header.tsx +++ b/apps/mobile/components/session-header.tsx @@ -80,7 +80,7 @@ function SessionHeaderInner({ className="flex flex-row gap-2 items-center border-b border-accent pb-2 px-4" style={{ paddingTop: paddingTop + 10 }} > -