diff --git a/packages/opencode/src/cli/cmd/tui/context/sdk.tsx b/packages/opencode/src/cli/cmd/tui/context/sdk.tsx index 41f69f0d9..fa3b1c633 100644 --- a/packages/opencode/src/cli/cmd/tui/context/sdk.tsx +++ b/packages/opencode/src/cli/cmd/tui/context/sdk.tsx @@ -1,7 +1,7 @@ import { createOpencodeClient, type Event } from "@opencode-ai/sdk" import { createSimpleContext } from "./helper" import { createGlobalEmitter } from "@solid-primitives/event-bus" -import { onCleanup } from "solid-js" +import { batch, onCleanup } from "solid-js" export const { use: useSDK, provider: SDKProvider } = createSimpleContext({ name: "SDK", @@ -17,8 +17,42 @@ export const { use: useSDK, provider: SDKProvider } = createSimpleContext({ }>() sdk.event.subscribe().then(async (events) => { + let queue: Event[] = [] + let timer: Timer | undefined + let last = 0 + + const flush = () => { + if (queue.length === 0) return + const events = queue + queue = [] + timer = undefined + last = Date.now() + // Batch all event emissions so all store updates result in a single render + batch(() => { + for (const event of events) { + emitter.emit(event.type, event) + } + }) + } + for await (const event of events.stream) { - emitter.emit(event.type, event) + queue.push(event) + const elapsed = Date.now() - last + + if (timer) continue + // If we just flushed recently (within 16ms), batch this with future events + // Otherwise, process immediately to avoid latency + if (elapsed < 16) { + timer = setTimeout(flush, 16) + continue + } + flush() + } + + // Flush any remaining events + if (timer) clearTimeout(timer) + if (queue.length > 0) { + flush() } })