(
part: Extract<OpencodePart, { type: 'text' }>,
delta: string | undefined,
)
| 187 | } |
| 188 | |
| 189 | function* handleTextPart( |
| 190 | part: Extract<OpencodePart, { type: 'text' }>, |
| 191 | delta: string | undefined, |
| 192 | ): Generator<StreamChunk> { |
| 193 | yield* closeReasoning() |
| 194 | |
| 195 | const prev = textAccumulators.get(part.id) ?? '' |
| 196 | let deltaText: string |
| 197 | if (typeof delta === 'string' && delta !== '') { |
| 198 | deltaText = delta |
| 199 | textAccumulators.set(part.id, prev + delta) |
| 200 | } else { |
| 201 | const full = part.text |
| 202 | deltaText = full.startsWith(prev) ? full.slice(prev.length) : full |
| 203 | textAccumulators.set(part.id, full) |
| 204 | } |
| 205 | if (deltaText === '') return |
| 206 | |
| 207 | if (openTextId !== part.id) { |
| 208 | yield* closeText() |
| 209 | openTextId = part.id |
| 210 | yield { |
| 211 | type: EventType.TEXT_MESSAGE_START, |
| 212 | messageId: part.id, |
| 213 | model, |
| 214 | timestamp: now(), |
| 215 | role: 'assistant', |
| 216 | } |
| 217 | } |
| 218 | yield { |
| 219 | type: EventType.TEXT_MESSAGE_CONTENT, |
| 220 | messageId: part.id, |
| 221 | model, |
| 222 | timestamp: now(), |
| 223 | delta: deltaText, |
| 224 | content: textAccumulators.get(part.id) ?? deltaText, |
| 225 | } |
| 226 | } |
| 227 | |
| 228 | function* handleReasoningPart( |
| 229 | part: Extract<OpencodePart, { type: 'reasoning' }>, |
no test coverage detected