11"use client" ;
22
33import { Loader2Icon } from "lucide-react" ;
4- import {
5- startTransition ,
6- useEffect ,
7- useId ,
8- useMemo ,
9- useRef ,
10- useState ,
11- } from "react" ;
4+ import { startTransition , useEffect , useId , useRef , useState } from "react" ;
125import { z } from "zod/mini" ;
136
147import { Terminal } from "@/components/ai-elements/terminal" ;
@@ -21,6 +14,7 @@ import {
2114 SelectTrigger ,
2215 SelectValue ,
2316} from "@/components/ui/select" ;
17+ import { tryReadJsonErrorMessage } from "@/lib/core/errors" ;
2418
2519type StreamStatus = "idle" | "streaming" | "done" | "error" ;
2620const STREAM_EVENT_FLUSH_MS = 16 ;
@@ -30,10 +24,6 @@ const startResponseSchema = z.looseObject({
3024 workflowRunId : z . optional ( z . string ( ) ) ,
3125} ) ;
3226
33- const errorResponseSchema = z . looseObject ( {
34- error : z . optional ( z . looseObject ( { message : z . optional ( z . string ( ) ) } ) ) ,
35- } ) ;
36-
3727const uiMessageChunkSchema = z . looseObject ( {
3828 data : z . optional ( z . unknown ( ) ) ,
3929 type : z . string ( ) ,
@@ -139,11 +129,6 @@ export function CodeModeClient(props: Readonly<{ projectId: string }>) {
139129 [ ] ,
140130 ) ;
141131
142- const streamStorageKey = useMemo (
143- ( ) => ( runId ? `workflow:code-mode:v1:${ runId } :startIndex` : null ) ,
144- [ runId ] ,
145- ) ;
146-
147132 const start = async ( ) => {
148133 abortRef . current ?. abort ( ) ;
149134 abortRef . current = new AbortController ( ) ;
@@ -175,15 +160,9 @@ export function CodeModeClient(props: Readonly<{ projectId: string }>) {
175160 }
176161
177162 if ( ! res . ok ) {
178- let message = `Failed to start Code Mode (${ res . status } ).` ;
179- try {
180- const jsonUnknown : unknown = await res . json ( ) ;
181- const parsed = errorResponseSchema . safeParse ( jsonUnknown ) ;
182- const fromServer = parsed . success ? parsed . data . error ?. message : null ;
183- if ( fromServer ) message = fromServer ;
184- } catch {
185- // Ignore.
186- }
163+ const fromServer = await tryReadJsonErrorMessage ( res ) ;
164+ const message =
165+ fromServer ?? `Failed to start Code Mode (${ res . status } ).` ;
187166 setStatus ( "error" ) ;
188167 setError ( message ) ;
189168 return ;
@@ -226,14 +205,14 @@ export function CodeModeClient(props: Readonly<{ projectId: string }>) {
226205 } ;
227206
228207 useEffect ( ( ) => {
229- if ( ! runId || ! streamStorageKey ) return ;
230- void reconnectSeed ;
208+ if ( ! runId ) return ;
209+ void reconnectSeed ; // Reference to trigger effect re-run on reconnect requests
231210
232211 const abort = abortRef . current ;
233212 if ( ! abort ) return ;
234213
235214 const currentRunId = runId ;
236- const storageKey = streamStorageKey ;
215+ const storageKey = `workflow:code-mode:v1: ${ currentRunId } :startIndex` ;
237216
238217 let startIndex = readStartIndex ( storageKey ) ;
239218 const autoReconnectDelaysMs = [ 250 , 750 , 1500 ] as const ;
@@ -280,15 +259,8 @@ export function CodeModeClient(props: Readonly<{ projectId: string }>) {
280259 }
281260
282261 if ( ! res . ok ) {
283- let message = `Failed to open stream (${ res . status } ).` ;
284- try {
285- const jsonUnknown : unknown = await res . json ( ) ;
286- const parsed = errorResponseSchema . safeParse ( jsonUnknown ) ;
287- const fromServer = parsed . success ? parsed . data . error ?. message : null ;
288- if ( fromServer ) message = fromServer ;
289- } catch {
290- // Ignore.
291- }
262+ const fromServer = await tryReadJsonErrorMessage ( res ) ;
263+ const message = fromServer ?? `Failed to open stream (${ res . status } ).` ;
292264 setError ( message ) ;
293265 setStatus ( "error" ) ;
294266 return "error" ;
@@ -471,7 +443,7 @@ export function CodeModeClient(props: Readonly<{ projectId: string }>) {
471443 setStatus ( "error" ) ;
472444 setError ( err instanceof Error ? err . message : "Stream disconnected." ) ;
473445 } ) ;
474- } , [ reconnectSeed , runId , streamStorageKey ] ) ;
446+ } , [ reconnectSeed , runId ] ) ;
475447
476448 const cancel = async ( ) => {
477449 if ( ! runId ) return ;
0 commit comments