feat: add opencode provider and refactor stream model to head/tail architecture
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
---
|
||||
id: 9b83b90a
|
||||
title: Refactor stream buffering to head/tail model
|
||||
status: open
|
||||
deps: []
|
||||
created: 2026-01-11T08:48:35.444Z
|
||||
---
|
||||
|
||||
## Goal
|
||||
|
||||
Replace the current special-case buffering logic with a unified head/tail model where:
|
||||
- **Tail**: Committed StreamItem[] (history)
|
||||
- **Head**: Active StreamItem[] (being streamed, same type as tail)
|
||||
|
||||
Both use the same `reduceStreamUpdate()` function. The only difference is that head items get flushed to tail when a stream item completes.
|
||||
|
||||
## Current Problems
|
||||
|
||||
1. `applyStreamEventWithBuffer()` has hardcoded assistant_message buffering
|
||||
2. `StreamingBufferEntry` is a different type than `StreamItem`
|
||||
3. Reasoning chunks go through reducer directly (no buffering)
|
||||
4. Duplicate logic between `appendAssistantMessage()` and buffer handling
|
||||
|
||||
## Design
|
||||
|
||||
### Types
|
||||
|
||||
```typescript
|
||||
// Head is just StreamItem[] - no special type needed
|
||||
// Tail is just StreamItem[] - same as before
|
||||
|
||||
interface StreamState {
|
||||
tail: StreamItem[]; // committed history
|
||||
head: StreamItem[]; // active streaming items
|
||||
}
|
||||
```
|
||||
|
||||
### Core Function
|
||||
|
||||
```typescript
|
||||
function applyStreamEvent(params: {
|
||||
tail: StreamItem[];
|
||||
head: StreamItem[];
|
||||
event: AgentStreamEventPayload;
|
||||
timestamp: Date;
|
||||
}): {
|
||||
tail: StreamItem[];
|
||||
head: StreamItem[];
|
||||
changedTail: boolean;
|
||||
changedHead: boolean;
|
||||
}
|
||||
```
|
||||
|
||||
### Flush Logic
|
||||
|
||||
Head items are flushed to tail when:
|
||||
1. A different item kind arrives (thought → tool_call flushes the thought)
|
||||
2. Turn completion events (turn_completed, turn_failed, turn_canceled)
|
||||
3. User message arrives (new turn starting)
|
||||
|
||||
### Implementation Steps
|
||||
|
||||
1. Remove `StreamingBufferEntry` type
|
||||
2. Remove `StreamingHead` type (or repurpose)
|
||||
3. Modify `applyStreamEventWithBuffer` → `applyStreamEvent` to work with head/tail
|
||||
4. Head uses same `reduceStreamUpdate` as tail
|
||||
5. Add flush logic based on item kind transitions
|
||||
6. Update session-context.tsx to use new API
|
||||
7. Update agent-stream-view.tsx to render head items
|
||||
8. Update session-store.ts types
|
||||
|
||||
## Flush Conditions
|
||||
|
||||
```typescript
|
||||
function shouldFlushHead(head: StreamItem[], incomingKind: StreamItemKind): boolean {
|
||||
if (head.length === 0) return false;
|
||||
const lastHeadKind = head[head.length - 1].kind;
|
||||
|
||||
// Different kind arriving = flush
|
||||
if (lastHeadKind !== incomingKind) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
```
|
||||
|
||||
## Rendering
|
||||
|
||||
In agent-stream-view.tsx:
|
||||
- Tail is rendered in FlatList (reversed, virtualized)
|
||||
- Head is rendered in ListHeaderComponent (always visible, not virtualized since it's small)
|
||||
|
||||
This is similar to current approach but head can now contain any StreamItem types.
|
||||
Reference in New Issue
Block a user