()
| 92 | |
| 93 | // Process the stream |
| 94 | const processStream = async () => { |
| 95 | try { |
| 96 | while (true) { |
| 97 | const { done, value } = await reader.read(); |
| 98 | if (done) break; |
| 99 | |
| 100 | // Convert the chunk to text |
| 101 | const chunk = new TextDecoder().decode(value); |
| 102 | const lines = chunk.split("\n"); |
| 103 | |
| 104 | // Process each SSE message |
| 105 | for (const line of lines) { |
| 106 | if (line.startsWith("data: ")) { |
| 107 | try { |
| 108 | const data = JSON.parse(line.slice(6)) as StreamResponse; |
| 109 | |
| 110 | // If we receive an error, set loading to false immediately |
| 111 | if (data.error) { |
| 112 | setState({ status: "error", error: data.error }); |
| 113 | setLoading(false); |
| 114 | return; // Add this to stop processing |
| 115 | } |
| 116 | |
| 117 | // Update state based on the message type |
| 118 | switch (data.status) { |
| 119 | case "started": |
| 120 | setState((prev) => ({ |
| 121 | ...prev, |
| 122 | status: "started", |
| 123 | message: data.message, |
| 124 | })); |
| 125 | break; |
| 126 | case "explanation_sent": |
| 127 | setState((prev) => ({ |
| 128 | ...prev, |
| 129 | status: "explanation_sent", |
| 130 | message: data.message, |
| 131 | })); |
| 132 | break; |
| 133 | case "explanation": |
| 134 | setState((prev) => ({ |
| 135 | ...prev, |
| 136 | status: "explanation", |
| 137 | message: data.message, |
| 138 | })); |
| 139 | break; |
| 140 | case "explanation_chunk": |
| 141 | if (data.chunk) { |
| 142 | explanation += data.chunk; |
| 143 | setState((prev) => ({ ...prev, explanation })); |
| 144 | } |
| 145 | break; |
| 146 | case "mapping_sent": |
| 147 | setState((prev) => ({ |
| 148 | ...prev, |
| 149 | status: "mapping_sent", |
| 150 | message: data.message, |
| 151 | })); |
no test coverage detected