Skip to content

F6a: interfaz de motor, corte por inactividad y actividad en vivo - #2

Merged
Jdrg4 merged 9 commits into
mainfrom
f6a-motor
Oct 15, 2026
Merged

Jdrg4 merged 9 commits into
mainfrom
f6a-motor

Conversation

@Jdrg4

@Jdrg4 Jdrg4 commented Oct 15, 2026

Copy link
Copy Markdown
Owner

Implementa la spec de F6a.

Qué cambia

  • AgentEngine: ReviewService ya no conoce opencode. OpencodeEngine junta pool de puertos, AgentSandbox, proceso y sesión; el motor no toca git ni GitHub.
  • Corte por inactividad en vez de reloj fijo: 10 min sin eventos de la sesión (los heartbeats no cuentan; una herramienta en marcha pausa el reloj). El techo del turno pasa a 6 h como red de seguridad.
  • Actividad en vivo en el hilo del job («Editando src/app.py», «Ejecutando un comando»). El proxy de Next pasa los text/event-stream sin bufferizar.
  • Errores del modelo legibles: un 500 de opencode se explica con su session.error («Model not found…»).
  • Catálogo: fuera los modelos deprecated de models.dev (opencode los oculta; deepseek-v4-flash moría así).
  • Banco de evals manual (python -m evals.run), con 3 tareas sobre un repo de prueba.

Verificación

  • Backend: 250 tests, ruff limpio. Frontend: 122 tests, tsc, lint, build.
  • Job real local contra vesper-testbed → PR F6a: interfaz de motor, corte por inactividad y actividad en vivo #2, con la actividad en vivo en el navegador (también a 390 px).
  • Evals con deepseek-v4-pro: bug-suma ✅, docstrings ✅, nada-que-hacer ✅ 3 de 4.
  • Revisión final de rama con Opus: 2 hallazgos importantes y 7 menores, todos aplicados con test.

🤖 Generated with Claude Code

Jdrg4 and others added 9 commits October 15, 2026 10:16
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Escucha el SSE de opencode durante el turno: cada evento de la sesión reinicia el
reloj (10 min por defecto; los heartbeats no cuentan y una herramienta en marcha lo
pausa), reenvía la herramienta en uso y recoge el motivo de session.error, que es lo
único que explica un 500 con un modelo desconocido. El techo del turno pasa a 6 h
como red de seguridad.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
El job ya no conoce opencode: pide un motor a engine_factory, le pasa workdir,
prompt, modelo y credenciales, y reenvía su actividad al SSE como evento
`activity` (una cada 3 s como mucho). Relojes: turno 6 h < job_timeout 6 h 15 min
< STALE 7 h.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
El proxy de Next pasa los text/event-stream sin bufferizar (antes res.text()
esperaba a que el backend cerrara) y el hilo abre un EventSource mientras el job
corre: «Editando src/app.py», «Ejecutando un comando»…

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
python -m evals.run --model <proveedor/modelo> corre el motor sobre una copia de un
repo de prueba con tres tareas (arreglar un bug, añadir docstrings, no tocar nada
cuando no hay nada que hacer) y saca una tabla. Las comprobaciones miran el diff y
la suite del fixture, y tienen sus propios tests con FakeEngine.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ra lo efímero

El banco aplica EPHEMERAL_PATTERNS como el flujo real (los .pyc de correr la suite no
cuentan como cambio) y, si una tarea suspende, dice qué archivos cambiaron.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…odelos obsoletos

Con opencode real el 500 de POST /message vuelve antes de que el SSE entregue
session.error: el motor cortaba la escucha y el job solo decía «500». Ahora espera
hasta 5 s al motivo. El caso que lo destapó: deepseek-v4-flash está marcado
deprecated en models.dev (renombrado a deepseek-flash) y opencode lo oculta, pero el
catálogo de Vesper lo seguía ofreciendo. El catálogo filtra los deprecated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Publicar la actividad (Redis) ya no puede tumbar el listener ni el job.
- Si el SSE se corta con una herramienta en marcha, se olvida: el corte por
  inactividad ya no queda pausado para siempre.
- El turno espera a que el SSE esté conectado (un error inmediato no se pierde).
- stop() libera el puerto aunque falle un paso previo y deja subir su propio cancel.
- La UI recibe también la última actividad de cada ráfaga, no solo la primera.
- Rutas relativas de opencode se leen contra el workspace.
- El proxy corta la petición al backend si el navegador se va; el hilo cierra el
  EventSource con el evento terminal.
- El banco de evals no se cae si un motor lanza otra excepción.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…er falso saluda como el real

opencode manda server.connected al suscribirse y FakeOpencodeRunner no: cada job de
test esperaba los 5 s de gracia y los de abortar se colgaban.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Jdrg4
Jdrg4 merged commit 12de869 into main Oct 15, 2026
2 of 3 checks passed
@Jdrg4
Jdrg4 deleted the f6a-motor branch October 15, 2026 16:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant