---
description: "Task list for feature 003-chat-streaming"
---

# Tasks: Streaming híbrido en chat de conversación

**Input**: Design documents from `/specs/003-chat-streaming/`

**Prerequisites**: plan.md, spec.md, research.md, data-model.md, contracts/chat-stream-sse.md, quickstart.md

**Tests**: Incluidos en fase Polish; spec no exige TDD estricto.

**Organization**: Tareas agrupadas por user story para implementación y prueba incremental independiente.

## Format: `[ID] [P?] [Story] Description`

- **[P]**: Paralelizable (archivos distintos, sin dependencias entre sí)
- **[Story]**: User story de spec.md (US1–US3)
- Rutas concretas en cada descripción

## Phase 1: Setup (Shared Infrastructure)

**Purpose**: Configuración compartida y verificación de feature

- [x] T001 Añadir sección `streaming` (`enabled`, `status_messages`) en `config/agent.php` según plan.md (FR-002)
- [x] T002 [P] Documentar variable `AGENT_STREAMING_ENABLED` en `specs/003-chat-streaming/quickstart.md` y `.env.example` si existe
- [x] T003 [P] Verificar feature pointer en `.specify/feature.json` apunta a `specs/003-chat-streaming`

---

## Phase 2: Foundational (Blocking Prerequisites)

**Purpose**: Contratos SSE, LLM streaming y tipos frontend — **bloquea todas las user stories**

**⚠️ CRITICAL**: Ninguna user story puede completarse hasta terminar esta fase

- [x] T004 Crear `AgentStreamEmitterInterface` (`status`, `chunk`, `done`, `error`) en `app/Contracts/Agent/AgentStreamEmitterInterface.php`
- [x] T005 [P] Crear DTO `ChatStreamEvent` con serialización SSE `toSseLine()` en `app/DTOs/ChatStreamEvent.php` según `specs/003-chat-streaming/contracts/chat-stream-sse.md`
- [x] T006 Implementar `SseStreamEmitter` que implementa `AgentStreamEmitterInterface` en `app/Services/Chat/SseStreamEmitter.php`
- [x] T007 Ampliar `LlmChatCompletionContract` con `chatStream(array $messages, callable $onChunk, array $options = []): string` en `app/Contracts/LlmChatCompletionContract.php`
- [x] T008 [P] Implementar `chatStream` en `app/Services/Llm/OpenAiLlmChatClient.php` (`stream: true`, acumular deltas)
- [x] T009 [P] Implementar `chatStream` en `app/Services/Llm/GeminiLlmChatClient.php` (`streamGenerateContent` o equivalente)
- [x] T010 [P] Añadir tipos `ChatStreamEvent`, `ChatStreamPhase`, `ChatStreamHandlers` en `ChatFront/src/app/core/models/api.types.ts`

**Checkpoint**: Infraestructura streaming lista — pueden empezar las user stories

---

## Phase 3: User Story 1 — Ver progreso mientras el asistente trabaja (Priority: P1) 🎯 MVP

**Goal**: Operador ve eventos de estado («Analizando…», «Consultando datos…», «Preparando respuesta…») antes del texto final

**Independent Test**: `curl -N POST /api/v1/chat/message/stream` devuelve al menos un evento `status` antes de `chunk`; UI muestra subtítulo de estado en bubble assistant (SC-001, SC-002)

### Implementation for User Story 1

- [x] T011 [US1] Crear esqueleto `ChatConversationStreamService` con `streamResponse(User, string, string): StreamedResponse` en `app/Services/ChatConversationStreamService.php`
- [x] T012 [US1] Persistir mensaje user al inicio del stream en `app/Services/ChatConversationStreamService.php` (data-model.md, FR-004)
- [x] T013 [US1] Implementar `handleStreaming(string $sessionId, string $text, string $referer, AgentStreamEmitterInterface $emitter): string` en `app/Services/Agent/AgentOrchestratorService.php` emitiendo `status: analyzing`
- [x] T014 [US1] Emitir `status: querying` durante ejecución SQL en `app/Services/Agent/Handlers/AgentDatabaseQueryCapabilityHandler.php` (método streaming o parámetro emitter opcional)
- [x] T015 [US1] Emitir `status: generating` antes de redacción LLM en handlers (`GeneralChatCapabilityHandler`, `AgentDatabaseQueryCapabilityHandler`)
- [x] T016 [US1] Añadir `messageStream()` delgado en `app/Http/Controllers/Api/V1/ChatController.php` delegando en `ChatConversationStreamService`
- [x] T017 [US1] Registrar `POST chat/message/stream` con `auth:api` y `throttle:30,1` en `routes/api.php` (FR-001, FR-005)
- [x] T018 [P] [US1] Implementar `streamConversationMessage()` con parser SSE vía `fetch` en `ChatFront/src/app/core/services/chat-api.service.ts`
- [x] T019 [US1] Actualizar `send()` y template en `ChatFront/src/app/features/conversation/conversation.component.ts` y `conversation.component.html`: bubble assistant con `statusMessage` signal; eliminar spinner estático «El asistente está pensando…» (FR-007)

**Checkpoint**: MVP status — usuario ve feedback de fase antes/durante procesamiento

---

## Phase 4: User Story 2 — Respuesta apareciendo progresivamente (Priority: P1)

**Goal**: Fragmentos de texto del asistente en tiempo real; persistencia completa al `done`

**Independent Test**: Mensaje texto en `/assistant` rellena bubble incrementalmente; recargar página muestra mensaje assistant completo idéntico (FR-003, SC-003)

### Implementation for User Story 2

- [x] T020 [US2] Integrar `chatStream` en `app/Services/Agent/Handlers/GeneralChatCapabilityHandler.php` reenviando deltas al emitter (FR-003)
- [x] T021 [US2] Refactorizar `interpretResultsAndRespond` para usar `chatStream` en `app/Services/Agent/Handlers/AgentDatabaseQueryCapabilityHandler.php`
- [x] T022 [US2] Acumular chunks y emitir `done` con `assistant_id` + `content` tras persistir assistant en `app/Services/ChatConversationStreamService.php` (FR-004, SC-003)
- [x] T023 [US2] En error/exception: emitir evento `error` sin persistir assistant parcial en `app/Services/ChatConversationStreamService.php` (FR-008, edge cases spec)
- [x] T024 [US2] Mapear excepciones LLM vía `DomainErrorMapper` a mensajes SSE amigables en `app/Services/ChatConversationStreamService.php`
- [x] T025 [US2] Append `chunk.content` al bubble streaming en `ChatFront/src/app/features/conversation/conversation.component.ts`
- [x] T026 [US2] Manejar evento `done`: fijar `assistant_id`, limpiar estado stream, `loadConversation({ silent: true })` en `conversation.component.ts`
- [x] T027 [US2] Manejar evento `error`: toast + revertir bubble parcial en `conversation.component.ts` (SC-005)
- [x] T028 [US2] Bloquear envío concurrente mientras `streaming()` activo en `conversation.component.ts`

**Checkpoint**: Streaming híbrido completo — estados + tokens + persistencia

---

## Phase 5: User Story 3 — Compatibilidad con adjuntos (Priority: P2)

**Goal**: PDF/JPG siguen flujo síncrono sin regresiones

**Independent Test**: Adjuntar PDF → usa `POST /chat/message`; respuesta al completar; `sending()` bloquea doble envío (FR-006, SC-004)

### Implementation for User Story 3

- [x] T029 [US3] En `send()` de `ChatFront/src/app/features/conversation/conversation.component.ts`: si `selectedFile` → `chatApi.sendConversationMessage()` síncrono; si solo texto → `streamConversationMessage()` (FR-006)
- [x] T030 [US3] Verificar `app/Services/ChatConversationService.php` sin cambios de comportamiento para adjuntos (regresión manual US3)
- [x] T031 [US3] Rechazar body con adjunto en endpoint stream (422 o documentar que no acepta multipart) en `app/Http/Controllers/Api/V1/ChatController.php`

**Checkpoint**: Adjuntos intactos; texto usa stream

---

## Phase 6: Polish & Cross-Cutting Concerns

**Purpose**: Tests, calidad, validación quickstart

- [x] T032 [P] Feature test `tests/Feature/Chat/ChatConversationStreamTest.php`: Content-Type SSE, orden eventos, assistant persistido
- [x] T033 [P] Unit test serialización en `tests/Unit/DTOs/ChatStreamEventTest.php`
- [x] T034 [P] Spec parser SSE en `ChatFront/src/app/core/services/chat-api.service.spec.ts` (crear si no existe)
- [x] T035 Ejecutar `vendor/bin/pint --dirty` en archivos PHP tocados
- [x] T036 Ejecutar `php artisan test --filter=ChatStream` y corregir fallos
- [x] T037 Ejecutar `ng build` en `ChatFront/` sin errores
- [x] T038 Validar escenarios manuales de `specs/003-chat-streaming/quickstart.md` (SC-001 a SC-005)

---

## Dependencies & Execution Order

### Phase Dependencies

- **Setup (Phase 1)**: Sin dependencias
- **Foundational (Phase 2)**: Depende de Setup — **BLOQUEA** US1, US2, US3
- **US1 (Phase 3)**: Depende de Phase 2 — MVP status
- **US2 (Phase 4)**: Depende de Phase 3 (endpoint + emitter wiring) — añade tokens y persistencia
- **US3 (Phase 5)**: Depende de Phase 4 (send() branching) — puede hacerse en paralelo con Polish si US2 done
- **Polish (Phase 6)**: Depende de US1–US3 deseados

### User Story Dependencies

| Story | Depende de | Notas |
|-------|------------|-------|
| US1 | Phase 2 | Independiente de US2/US3 para probar solo status |
| US2 | US1 (endpoint + UI bubble) | Añade chunks; no requiere US3 |
| US3 | US2 (send branching) | Solo frontend branch + verificación sync |

### Parallel Opportunities

**Phase 2** (tras T004–T007 secuenciales):
```text
T008 OpenAiLlmChatClient.php ∥ T009 GeminiLlmChatClient.php ∥ T010 api.types.ts
```

**Phase 3** (tras T011–T017 backend):
```text
T018 chat-api.service.ts ∥ T019 conversation.component (si API lista)
```

**Phase 6**:
```text
T032 ChatConversationStreamTest.php ∥ T033 ChatStreamEventTest.php ∥ T034 chat-api.service.spec.ts
```

---

## Parallel Example: User Story 1

```bash
# Tras T017 (ruta registrada), en paralelo:
# T018 — ChatFront/src/app/core/services/chat-api.service.ts
# T019 — conversation.component.ts + .html

# Tras Phase 2, backend US1 secuencial recomendado:
# T011 → T012 → T013 → T014 → T015 → T016 → T017
```

---

## Implementation Strategy

### MVP First (User Story 1)

1. Phase 1 + Phase 2 (fundación)
2. Phase 3 (US1): status events visibles en UI
3. **STOP and VALIDATE**: curl + UAT SC-001/SC-002
4. Demo: ya no parece «colgado» durante consultas BD

### Incremental Delivery

1. US1 → status feedback (MVP percepción)
2. US2 → tokens progresivos + persistencia (experiencia ChatGPT)
3. US3 → adjuntos sin regresión
4. Polish → tests + quickstart

### Suggested MVP Scope

**Phase 1 + 2 + 3 (T001–T019)** entrega valor SC-001/SC-002 sin streaming de tokens completo. Completar **Phase 4** para FR-003 y SC-003.

---

## Notes

- Total tasks: **38**
- US1: **9** tasks (T011–T019)
- US2: **9** tasks (T020–T028)
- US3: **3** tasks (T029–T031)
- Setup: **3** | Foundational: **7** | Polish: **7**
- Contrato SSE: `specs/003-chat-streaming/contracts/chat-stream-sse.md`
- Endpoint sync conservado: `POST /api/v1/chat/message` para adjuntos y fallback
