Repository navigation
Implement useStreaming hook for chat responses #11772
Copy link
Copy link
Closed as not planned
Labels
opentuiThis relates to changes in v1.0, now that opencode uses opentuiThis relates to changes in v1.0, now that opencode uses opentui
Description
Parent Epic
Part of #11762 (Ink-based TUI Rewrite)
Objective
Create React hook that handles streaming chat responses, managing the connection between user input and assistant output.
Architecture
function useStreaming(sessionId: string | null) {
const [isStreaming, setIsStreaming] = useState(false)
const [streamingText, setStreamingText] = useState('')
const [error, setError] = useState<Error | null>(null)
const sendMessage = useCallback(async (content: string) => {
if (!sessionId || isStreaming) return
setIsStreaming(true)
setStreamingText('')
setError(null)
try {
const response = await fetch(`http://localhost:${port}/session/${sessionId}/message`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ content })
})
const reader = response.body?.getReader()
const decoder = new TextDecoder()
while (true) {
const { done, value } = await reader.read()
if (done) break
const chunk = decoder.decode(value)
// Parse SSE chunks, extract text deltas
for (const line of chunk.split('\n')) {
if (line.startsWith('data: ')) {
const data = JSON.parse(line.slice(6))
if (data.type === 'text') {
setStreamingText(prev => prev + data.content)
}
}
}
}
} catch (err) {
setError(err as Error)
} finally {
setIsStreaming(false)
}
}, [sessionId, isStreaming])
const cancel = useCallback(() => {
// Send cancel signal
}, [])
return { isStreaming, streamingText, error, sendMessage, cancel }
}Integration with State
const App = () => {
const [state, dispatch] = useReducer(reducer, initialState)
const { isStreaming, streamingText, sendMessage, cancel } = useStreaming(state.session.id)
// SDK events update tools/tasks
useSDKEvents(state.session.id, dispatch)
// When streaming ends, complete the message
useEffect(() => {
if (!isStreaming && streamingText) {
dispatch({ type: 'MESSAGE_COMPLETE', text: streamingText })
}
}, [isStreaming, streamingText])
return (
<Box flexDirection="column">
<Static items={state.messages}>...</Static>
<LiveSection
text={streamingText}
tools={state.streaming.tools}
tasks={state.streaming.tasks}
isStreaming={isStreaming}
/>
<InputLine onSubmit={sendMessage} onCancel={cancel} disabled={isStreaming} />
</Box>
)
}Tasks
- Create
src/cli/ink/hooks/useStreaming.ts - Implement message sending
- Implement SSE stream parsing
- Handle text delta accumulation
- Implement cancel functionality
- Handle errors gracefully
- Integrate with markdown rendering
Acceptance Criteria
- Messages send successfully
- Streaming text appears incrementally
- Cancel works during streaming
- Errors display appropriately
- Input disabled during streaming
Estimated Effort
1.5 days
Risk
Medium - SSE parsing can be tricky
Dependencies
- Setup Ink dependencies and verify Bun compatibility #11763 (Setup Ink dependencies)
- Implement core App component and state management #11764 (App component)
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
opentuiThis relates to changes in v1.0, now that opencode uses opentuiThis relates to changes in v1.0, now that opencode uses opentui
Activity
randomm commentedon Feb 3, 2026
Reopening - Phase 1 & 2 components merged successfully. Proceeding with hook implementation.