Skip to content

Commit 802a78e

Browse files
committed
Merge fix/message-truncation
2 parents 251310b + 6613472 commit 802a78e

File tree

1 file changed

+26
-0
lines changed
  • packages/opencode/src/cli/cmd/tui/context

1 file changed

+26
-0
lines changed

packages/opencode/src/cli/cmd/tui/context/sync.tsx

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,32 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({
215215
}
216216
const result = Binary.search(parts, event.properties.part.id, (p) => p.id)
217217
if (result.found) {
218+
// For TextParts during streaming, use produce to merge deltas safely
219+
// This prevents race conditions where text-end overwrites accumulated text
220+
const currentPart = parts[result.index]
221+
if (currentPart.type === "text" && event.properties.part.type === "text") {
222+
const incomingTextPart = event.properties.part as Extract<Part, { type: "text" }>
223+
const currentTextPart = currentPart as Extract<Part, { type: "text" }>
224+
225+
// If this is a streaming update (has text field), use produce for safe merge
226+
if (incomingTextPart.text !== undefined) {
227+
setStore(
228+
"part",
229+
event.properties.part.messageID,
230+
produce((draft) => {
231+
const part = draft[result.index] as Extract<Part, { type: "text" }>
232+
// Update text content but preserve other metadata
233+
part.text = incomingTextPart.text
234+
// Update timing only if end time is provided (text-end event)
235+
if (incomingTextPart.time?.end) {
236+
part.time = incomingTextPart.time
237+
}
238+
})
239+
)
240+
break
241+
}
242+
}
243+
// Fall back to reconcile for non-text parts or non-streaming updates
218244
setStore("part", event.properties.part.messageID, result.index, reconcile(event.properties.part))
219245
break
220246
}

0 commit comments

Comments
 (0)