## ADDED Requirements

### Requirement: Streaming chat response
服务层 SHALL 使用 `fetch` + `ReadableStream` 实现流式对话，通过 `AsyncGenerator<SSEEvent>` 供上层消费。

#### Scenario: Successful streaming
- **WHEN** 调用 `speak(sessionId, audioBlob)` 发起请求
- **THEN** 依次 yield `transcript`、`token`（多次）、`done` 事件

#### Scenario: Empty response
- **WHEN** 后端返回空的 stream（0 tokens）
- **THEN** generator 正常结束，不抛异常

### Requirement: Request cancellation
每个流式请求 SHALL 支持通过 `AbortController` 取消。

#### Scenario: User cancels during streaming
- **WHEN** 流式输出进行中调用 `signal.abort()`
- **THEN** fetch 请求被取消，generator 抛出 `AbortError`，上层保留已接收内容

### Requirement: Error handling
请求失败时 SHALL 统一抛出错误，不区分错误类型（v1 简化版）。

#### Scenario: Request fails
- **WHEN** 网络断开、超时、或后端返回错误
- **THEN** 抛出 Error，上层将消息状态设为 `error`，显示重试按钮

### Requirement: Adapter interface
服务层 SHALL 通过 `DialogueAPI` 接口抽象后端通信，支持 mock 和真实 API 切换。

```typescript
interface DialogueAPI {
  createSession(config: SessionConfig): Promise<SessionInfo>
  speak(sessionId: string, audioBlob: Blob, signal: AbortSignal): AsyncGenerator<SSEEvent>
  getReport(sessionId: string): Promise<Report>
}
```

#### Scenario: Using mock adapter
- **WHEN** `mode` 为 `preview` 时
- **THEN** 使用 `MockDialogueAPI`，模拟 transcript + 逐 token 输出

#### Scenario: Using real adapter
- **WHEN** `mode` 为 `real` 时
- **THEN** 使用 `RealDialogueAPI`，对接后端 3 个接口

### Requirement: SSE response parsing
服务层 SHALL 解析后端返回的 SSE 格式流。

#### Scenario: Parse SSE events
- **WHEN** 后端返回 `event: transcript\ndata: {...}\n\n` 格式
- **THEN** 根据 event type 解析为对应的 SSEEvent 对象（transcript / token / done）
