Lab Notes
Tooling

Media Lab Server

El servidor HTTP local (`127.0.0.1:8765`) para generación de imágenes y música. Arquitectura, API, ciclo de vida e integración con el Coordinator.

Estado

Implemented. El servidor es un proceso standalone que el Coordinator llama a través de HTTP. Corre en el host local y no se expone a internet.

Propósito

El Media Lab Server es un pequeño servicio HTTP que expone las capacidades de generación de imágenes y música del lab a través de una web UI y una API HTTP. El Coordinator llama a la API para generar imágenes y música en respuesta a requests del usuario; el usuario también puede visitar la web UI directamente en un navegador.

Esta página documenta la arquitectura del servidor, los endpoints, el ciclo de vida y la integración con el Coordinator.

Por qué un servidor, no una herramienta CLI

Se prefiere un servidor sobre una herramienta CLI para generación porque:

  • UI con estado. Una web UI puede mostrar progreso, histórico y descargas.
  • Requests de larga duración. La generación puede tardar 30 segundos a 3 minutos; una request HTTP encaja naturalmente.
  • Aislamiento del host de modelos. El servidor se puede reiniciar independientemente del Coordinator.
  • Múltiples clientes. El usuario puede golpear la UI desde un navegador mientras el Coordinator también llama a la API.

El servidor es el único servidor HTTP del lab que expone capacidades de generación.

Dirección de escucha y puerto

CampoValorRazón
Host127.0.0.1Solo localhost; no se expone a la LAN o WAN.
Port8765Reservado para el Media Lab Server.
ProtocolHTTP/1.1Simple; no se necesita TLS porque es localhost.

El servidor está bindeado a localhost solo. No es alcanzable desde la LAN o internet. El usuario puede acceder a la UI en http://127.0.0.1:8765/ en un navegador de la misma máquina.

Arquitectura

El servidor es un proceso Python. La arquitectura:

Loading diagram…
Arquitectura del Media Lab Server: HTTP API, web UI, job queue in-process, image y music workers, output directory.

El servidor tiene:

  • Una HTTP API que acepta job requests.
  • Una web UI que envía jobs y muestra progreso.
  • Un job queue que serializa las requests de generación.
  • Un image worker que llama al modelo de imagen.
  • Un music worker que llama al modelo de música.
  • Un output directory donde se escriben los resultados.

Endpoints

GET /api/status

Devuelve el health del servidor y la carga actual.

Response (200):

{
  "status": "ok",
  "version": "0.4.0",
  "queue": {
    "pending": 0,
    "running": 0,
    "completed": 12
  },
  "models": {
    "image": "image-01",
    "music": "Music-2.6"
  }
}

POST /api/image

Envía un job de generación de imagen.

Request:

{
  "prompt": "A sunset over the ocean, oil painting style",
  "size": "1024x1024",
  "quality": "high",
  "count": 1
}

Response (202):

{
  "job_id": "img_abc123",
  "status": "pending",
  "poll_url": "/api/jobs/img_abc123"
}

POST /api/music

Envía un job de generación de música.

Request:

{
  "prompt": "Lo-fi hip hop, rainy night, piano and vinyl crackle",
  "duration_s": 120,
  "instrumental": true
}

Response (202):

{
  "job_id": "mus_def456",
  "status": "pending",
  "poll_url": "/api/jobs/mus_def456"
}

GET /api/jobs/<id>

Consulta el status de un job.

Response (200) para un image job completado:

{
  "job_id": "img_abc123",
  "type": "image",
  "status": "completed",
  "created_at": "2026-06-10T22:30:00Z",
  "completed_at": "2026-06-10T22:30:42Z",
  "outputs": [
    {
      "url": "/outputs/img_abc123_0.png",
      "size_bytes": 1843200
    }
  ]
}

Response (200) para un music job completado:

{
  "job_id": "mus_def456",
  "type": "music",
  "status": "completed",
  "created_at": "2026-06-10T22:30:00Z",
  "completed_at": "2026-06-10T22:32:18Z",
  "outputs": [
    {
      "url": "/outputs/mus_def456_0.mp3",
      "duration_s": 120,
      "size_bytes": 2400000
    }
  ]
}

Response (200) para un job running:

{
  "job_id": "img_abc123",
  "status": "running",
  "progress": 0.65
}

GET /api/jobs

Lista jobs recientes. Paginación mediante ?limit=N&offset=M.

Response:

{
  "total": 50,
  "limit": 20,
  "offset": 0,
  "jobs": [
    {"job_id": "img_abc123", "type": "image", "status": "completed", "created_at": "..."},
    {"job_id": "mus_def456", "type": "music", "status": "completed", "created_at": "..."}
  ]
}

GET /outputs/<file>

Devuelve el fichero generado. Endpoint estático; la ruta del fichero es el nombre del fichero en el output directory.

GET /

La web UI. Single-page application que envía jobs y muestra progreso.

Ciclo de vida del job

Un job pasa por estos estados:

Loading diagram…
Máquina de estados del ciclo de vida del job: pending → running → completed o failed.
StatusSignificado
pendingEl job está en la cola; ningún worker lo ha recogido.
runningUn worker está generando el output.
completedEl output está listo; el campo outputs está poblado.
failedLa generación falló; el campo error está poblado.

La máquina de estados es in-process; la cola es una lista en memoria. Si el servidor se reinicia, la cola se pierde. Los jobs pending los reenvía el cliente.

Generación de imágenes

El image worker llama a la API de imagen del provider de modelos. El modelo por defecto es image-01. Los tamaños soportados:

SizeCaso de uso
512x512thumbnails, small previews
1024x1024default, square images
1536x1024landscape images
1024x1536portrait images
2048x2048high-resolution images

La imagen se devuelve en PNG por defecto. El output se escribe en el output directory como img_<job_id>_<index>.png.

La duración media de generación es:

SizeDuración media
512x5128-12 s
1024x102412-18 s
1536x102418-25 s
2048x204830-45 s

La duración depende de la carga del provider.

Generación de música

El music worker llama a la API de música del provider. El modelo por defecto es Music-2.6. Los parámetros soportados:

ParámetroDefaultRangoNotas
duration_s601 to 300El provider cap a 5 min
instrumentaltrueboolSi false, lyrics requerido
lyrics(none)stringRequerido si instrumental: false
temperature1.00.0 to 2.0Mayor = más creativo
seed(none)integerOutputs reproducibles

El output es MP3 por defecto. El output se escribe en el output directory como mus_<job_id>_<index>.mp3.

La duración media de generación:

DurationDuración media
30 s30-60 s
60 s60-120 s
120 s120-240 s
300 s300-600 s

Gestión de quota

El servidor trackea la quota diaria para generación de imágenes y música. La quota se resetea a medianoche UTC. Las quotas por defecto son:

RecursoQuota diariaFuente
Image50 images/dayPlan default
Music100 songs/dayPlan default

El servidor rechaza jobs que excederían la quota con 429 Too Many Requests y un body JSON:

{
  "error": "quota_exhausted",
  "resource": "image",
  "used": 50,
  "limit": 50,
  "resets_at": "2026-06-11T00:00:00Z"
}

El Coordinator comprueba la quota antes de enviar un job para evitar round-trips desperdiciados.

Output directory

El servidor escribe outputs en ~/.openclaw/media/outbound/ por defecto. El Coordinator puede configurar la ruta mediante la variable de entorno MEDIA_LAB_OUTPUT_DIR.

La estructura del directorio:

~/.openclaw/media/outbound/
├── img_<job_id>_<index>.png
├── mus_<job_id>_<index>.mp3
└── .trash/
    └── <ficheros movidos a trash, retenidos 7 días>

Los ficheros antiguos los limpia un job de retención que corre diario a las 03:00 hora local. La retención por defecto es 30 días.

Ciclo de vida

El servidor está supervisado por launchd (macOS) o systemd (Linux). Las responsabilidades del supervisor:

  • Start on boot. El servidor arranca cuando el usuario hace login.
  • Restart on crash. El supervisor reinicia el servidor si crashea.
  • Reload on configuration change. El supervisor envía SIGHUP para recargar la configuración.

Launchd plist (macOS)

El plist está en {workspace-root}/services/media-lab-server/launchd.plist. El label de launchd es ai.openclaw.media-lab-server. El log del supervisor está en ~/.openclaw/media/logs/launchd.out.log.

Systemd unit (Linux)

La unit está en /etc/systemd/system/openclaw-media-lab.service. El nombre de la unit es openclaw-media-lab. El log de la unit está en /var/log/openclaw/media-lab.log.

Configuración

La configuración del servidor está en {workspace-root}/.openclaw/media-lab-server/config.toml.

CampoDefaultPropósito
host127.0.0.1Bind address.
port8765Bind port.
output_dir~/.openclaw/media/outbound/Output directory.
retention_days30Retención de outputs.
image_modelimage-01Modelo de imagen por defecto.
music_modelMusic-2.6Modelo de música por defecto.
quota_image50Quota diaria de imagen.
quota_music100Quota diaria de música.
log_levelINFOLog level.
log_formatjsonLog format.

Logging

El servidor loguea a ~/.openclaw/media/logs/server.log. El formato es JSON Lines por defecto. Cada entrada de log incluye:

  • timestamp: ISO 8601 UTC.
  • level: INFO, WARN, ERROR.
  • event: el nombre del evento (p. ej., job_submitted, job_started, job_completed).
  • job_id: el ID del job.
  • duration_ms: para jobs completados.
  • error: para jobs fallidos.

Ejemplo:

{"timestamp": "2026-06-10T22:30:00Z", "level": "INFO", "event": "job_submitted", "job_id": "img_abc123", "type": "image"}
{"timestamp": "2026-06-10T22:30:42Z", "level": "INFO", "event": "job_completed", "job_id": "img_abc123", "type": "image", "duration_ms": 42000}

Health checks

El servidor expone GET /api/status para health checks. El Coordinator y los scripts de auditoría consultan este endpoint periódicamente. La response esperada es 200 OK con el status del servidor.

Un health check fallido indica:

  • El servidor está caído (reiniciar el supervisor).
  • El servidor está sobrecargado (esperar y reintentar).
  • El provider de modelos está caído (comprobar la página de status del provider).

Failure modes

FailureResultado
El provider de modelos está caídoDevolver failed con el error del provider.
Quota exhaustedDevolver 429 con info de quota.
Output directory está llenoDevolver failed con error de disco lleno.
Job queue está llenoDevolver 503 con header retry-after.
El servidor crasheaEl supervisor lo reinicia. La cola se pierde.
Restart durante un jobEl job se pierde; el cliente debe reenviarlo.

Integración con el Coordinator

El Coordinator llama al servidor a través de la API. El flujo típico del Coordinator:

Loading diagram…
Flujo Coordinator → Media Lab Server: quota check, submit, poll, deliver.

El Coordinator hace polling al job hasta que esté completed o failed. El intervalo de polling es 5 segundos para image jobs, 10 segundos para music jobs.

Seguridad

El servidor está bindeado a localhost. No requiere autenticación porque los únicos clientes son procesos locales. Si el usuario quiere exponer el servidor a la LAN (p. ej., para llamar desde un teléfono), el usuario debe:

  1. Cambiar el bind address a 0.0.0.0.
  2. Añadir un reverse proxy (p. ej., nginx) con TLS.
  3. Añadir autenticación (p. ej., un token en el header de la request).

El lab no provee estas features out of the box.

Ver también