# Local Model Service Protocol (LMSP) 1.0, Borrador > Made for Agent publica protocolos abiertos y legibles por máquina que permiten a los agentes de IA, a los modelos y a las herramientas descubrirse y comunicarse entre sí. Empieza con LMSP, el Local Model Service Protocol. Source: https://madeforagent.com/es/llms-full.txt Updated: 2026-11-08 --- # Protocolo de Servicio de Modelos Locales (LMSP) > LMSP es un protocolo abierto para descubrir e invocar los modelos de lenguaje de tu dispositivo. Define descubrimiento de servicios, catálogo de modelos, streaming, tareas persistentes y compatibilidad con OpenAI. Source: https://madeforagent.com/es/lmsp/ Language: es Updated: 2026-11-08 ## Qué hace LMSP {#what} LMSP (Local Model Service Protocol) es un protocolo abierto para el software que ejecuta modelos de lenguaje en el propio dispositivo o en la red local del usuario, y para los clientes que usan ese software. Un servicio local residente se describe a sí mismo en una dirección conocida y lista sus modelos. Responde a las solicitudes de generación con JSON o con eventos enviados por el servidor, y ejecuta las generaciones largas como tareas persistentes que se pueden cancelar y volver a seguir después de una desconexión. El mismo servicio también habla la API de OpenAI, de modo que los clientes que existen hoy siguen funcionando. LMSP no sustituye a la API de OpenAI, a Ollama ni a MCP. Combina sus puntos fuertes en una capa de protocolo pensada para servicios locales residentes. ## De un vistazo {#glance} | Tema | Resumen | | --- | --- | | Dirección por defecto | `http://127.0.0.1:17832` | | Descripción del servicio | `GET /.well-known/lmsp.json` | | Interfaz principal | `/lmsp/v1`, JSON sobre HTTP, streaming con eventos enviados por el servidor | | Interfaces de compatibilidad | `/v1` para clientes OpenAI, `/api` opcional para clientes Ollama | | Descubrimiento | Dirección manual, sondeo de direcciones locales, mDNS y DNS-SD opcionales (`_lmsp._tcp.local.`) | | Autenticación | Tokens de portador obtenidos mediante emparejamiento local | | Persistencia | SQLite integrado, con tareas que sobreviven a un reinicio | | Contrato | OpenAPI 3.2 | ## Pruébalo {#try} Si hay un servicio LMSP ejecutándose en tu equipo, este es todo el flujo. Empareja primero para obtener un token, como se describe en la [sección 10.2](https://madeforagent.com/es/lmsp/1.0/security.md#pairing), y guárdalo en `LMSP_TOKEN`. ```sh # 1. Descubrir el servicio curl http://127.0.0.1:17832/.well-known/lmsp.json # 2. Listar los modelos locales curl http://127.0.0.1:17832/lmsp/v1/models \ -H "Authorization: Bearer $LMSP_TOKEN" # 3. Generar una respuesta curl http://127.0.0.1:17832/lmsp/v1/responses \ -H "Authorization: Bearer $LMSP_TOKEN" \ -H "Content-Type: application/json" \ -d '{"model":"qwen3:14b-q4_k_m","input":[{"type":"message","role":"user","content":[{"type":"input_text","text":"Hello"}]}]}' ``` ## Cómo se relaciona LMSP con otros protocolos {#related} | Protocolo | Qué cubre | Relación con LMSP | | --- | --- | --- | | API de OpenAI | Modelos alojados. La API Responses es su interfaz más reciente. | LMSP sigue la estructura de Responses para su interfaz principal, y un servicio ofrece junto a ella una interfaz compatible con OpenAI. | | Ollama | Un entorno de ejecución local que ya sirve endpoints compatibles con OpenAI. | Puede colocarse detrás de un servicio LMSP como adaptador, y LMSP define endpoints opcionales compatibles con Ollama. | | MCP | Conecta agentes con herramientas y contexto. | LMSP conecta agentes con modelos. Ambos prefieren el descubrimiento sin estado a las sesiones obligatorias. | | A2A | Colaboración entre agentes. | LMSP toma prestadas las tarjetas de servicio y los estados explícitos de las tareas para su descripción del servicio y sus tareas. | ## Recursos {#resources} - La [especificación, versión 1.0 (borrador)](https://madeforagent.com/es/lmsp/1.0.md). - El contrato OpenAPI, en [JSON](https://madeforagent.com/lmsp/1.0/openapi.json) o [YAML](https://madeforagent.com/lmsp/1.0/openapi.yaml). - [llms.txt](https://madeforagent.com/es/llms.txt) y [llms-full.txt](https://madeforagent.com/es/llms-full.txt), para modelos de lenguaje. - Cada página está disponible en Markdown. Sustituye la barra final de su dirección por `.md`, por ejemplo [`/es/lmsp/1.0/tasks.md`](https://madeforagent.com/es/lmsp/1.0/tasks.md). ## Preguntas frecuentes ### ¿Qué es LMSP? LMSP, el Local Model Service Protocol (Protocolo de Servicio de Modelos Locales), es un protocolo abierto para servicios de modelos de lenguaje que se ejecutan en el propio dispositivo del usuario o en su red local. Define cómo los clientes descubren un servicio, listan sus modelos, solicitan respuestas, reciben la salida en streaming y ejecutan tareas largas. ### ¿Sustituye LMSP a la API de OpenAI, a Ollama o a MCP? No. LMSP se apoya en ellos. Su interfaz principal sigue la estructura de OpenAI Responses, un servicio puede ofrecer endpoints compatibles con OpenAI y con Ollama, y el protocolo toma de MCP el descubrimiento sin estado y de A2A los estados de las tareas. ### ¿Pueden los clientes OpenAI existentes usar un servicio LMSP? Normalmente sí. Necesitan otra URL base y el token de LMSP como clave de API. No encuentran el servicio automáticamente, porque el descubrimiento requiere un cliente compatible con LMSP. ### ¿Cómo encuentra un cliente un servicio LMSP local? Prueba tres cosas por orden. Primero una dirección introducida a mano; después la dirección local convencional, donde solicita /.well-known/lmsp.json; y por último, de forma opcional, la exploración mDNS y DNS-SD de _lmsp._tcp.local. en la red local. ### ¿Es seguro un servicio de modelos en localhost? No automáticamente, porque las páginas web pueden intentar acceder a puertos locales. Los servicios LMSP se enlazan a loopback por defecto, exigen tokens de portador obtenidos mediante emparejamiento local, comprueban las cabeceras Origin y Host y exigen autenticación en modo LAN. ### ¿Cuál es el estado de la especificación? La versión 1.0 es un primer borrador público y todavía puede cambiar de forma incompatible. El texto en inglés es el normativo, y las traducciones se ofrecen por comodidad. --- # Visión general > Visión general del borrador de LMSP 1.0. Qué es el Local Model Service Protocol, los diseños en los que se apoya, su arquitectura por capas, cómo leer la especificación y los términos que se usan en todo el texto. Source: https://madeforagent.com/es/lmsp/1.0/ Language: es Specification: LMSP 1.0 (draft) Updated: 2026-11-08 ## 1.1 Resumen {#abstract} El Local Model Service Protocol (LMSP) define cómo los clientes encuentran y usan servicios de modelos de lenguaje que se ejecutan en el propio dispositivo o en la red local del usuario. Especifica el descubrimiento de servicios, un catálogo de modelos, la generación síncrona y en streaming, y tareas asíncronas que sobreviven a los reinicios. También define cómo un mismo servicio ofrece una interfaz compatible con OpenAI junto a la interfaz LMSP, de modo que los clientes existentes sigan funcionando. LMSP no sustituye a la API de OpenAI, a Ollama ni a MCP. Combina sus puntos fuertes en una capa de protocolo pensada para un servicio local residente. ## 1.2 Estado de este documento {#status} Este es el primer borrador público de LMSP 1.0, publicado el 2026-11-08. «LMSP» es un nombre provisional. El texto está abierto a comentarios y puede cambiar de forma incompatible hasta que 1.0 sea definitivo. El texto en inglés es normativo. Las traducciones se ofrecen por comodidad; si difieren, prevalece el texto en inglés. ## 1.3 Base del diseño {#design-basis} LMSP reutiliza diseños probados en lugar de inventar otros nuevos: - **API OpenAI Responses.** Elementos de salida estructurados, eventos semánticos enviados por el servidor y ejecución en segundo plano con consulta y cancelación para el trabajo de larga duración. Es la referencia de la interfaz de conversación principal de LMSP. Consulta [respuestas en streaming](https://developers.openai.com/api/docs/guides/streaming-responses) y [modo en segundo plano](https://developers.openai.com/api/docs/guides/background). - **Ollama.** Sirve los endpoints compatibles con OpenAI `/v1/models`, `/v1/chat/completions` y `/v1/responses`, lo que demuestra que un servicio más una capa de adaptación a OpenAI reduce drásticamente el coste de adopción. Consulta la [compatibilidad de Ollama con OpenAI](https://docs.ollama.com/api/openai-compatibility). - **Model Context Protocol (MCP).** Su diseño más reciente pasa de la inicialización obligatoria de sesión al descubrimiento sin estado: cada solicitud lleva su propia información de versión, y los clientes conocen las capacidades mediante una interfaz de descubrimiento. Eso encaja con los servicios locales, donde los reinicios, los fallos de los clientes y las conexiones interrumpidas no deben corromper el estado del protocolo. Consulta [MCP](https://modelcontextprotocol.io/). - **Agent2Agent (A2A).** Las tarjetas de servicio, los estados explícitos de las tareas, la suscripción a tareas y la cancelación inspiran la descripción del servicio y el modelo de tareas asíncronas de LMSP. Consulta [A2A](https://a2a-protocol.org/). ## 1.4 Arquitectura {#architecture} LMSP se organiza en tres capas, sobre los adaptadores que hablan con los entornos de ejecución de modelos: ```text +---------------------------------------------------------------+ | Discovery mDNS / DNS-SD + well-known service document | +---------------------------------------------------------------+ | Core model catalog, responses, SSE, async tasks | +---------------------------------------------------------------+ | Compatibility OpenAI API, optional Ollama API | +---------------------------------------------------------------+ | Adapters llama.cpp, Ollama, vLLM, custom runtimes | +---------------------------------------------------------------+ ``` - **Descubrimiento.** mDNS/DNS-SD y un documento de descripción del servicio en una dirección conocida ([página 3](https://madeforagent.com/es/lmsp/1.0/discovery.md)). - **Núcleo.** El catálogo de modelos, las respuestas síncronas, los eventos enviados por el servidor y las tareas asíncronas ([páginas 5 a 7](https://madeforagent.com/es/lmsp/1.0/models.md)). - **Compatibilidad.** Una API compatible con OpenAI y, opcionalmente, una API compatible con Ollama ([página 8](https://madeforagent.com/es/lmsp/1.0/compatibility.md)). - **Adaptadores.** Puentes hacia llama.cpp, Ollama, vLLM o un entorno de ejecución propio. El principio rector es **un único núcleo de ejecución de modelos, dos familias de interfaces**. Un servicio ofrece la interfaz LMSP y la interfaz OpenAI sobre el mismo núcleo, de modo que hay un único lugar donde se cargan los modelos, se ejecutan las solicitudes y se hace el seguimiento de las tareas. ## 1.5 Lenguaje de conformidad {#conformance} Las palabras clave **DEBE/DEBEN** (MUST), **NO DEBE/NO DEBEN** (MUST NOT), **OBLIGATORIO** (REQUIRED), **DEBERÍA/DEBERÍAN** (SHOULD), **NO DEBERÍA/NO DEBERÍAN** (SHOULD NOT), **RECOMENDADO** (RECOMMENDED), **PUEDE/PUEDEN** (MAY) y **OPCIONAL** (OPTIONAL) de este documento se interpretan como se describe en [BCP 14](https://www.rfc-editor.org/info/bcp14) ([RFC 2119](https://www.rfc-editor.org/rfc/rfc2119), [RFC 8174](https://www.rfc-editor.org/rfc/rfc8174)) cuando, y solo cuando, aparecen en negrita y en mayúsculas. Fuera de ese caso son palabras corrientes. Cada página está marcada como normativa o informativa. Las páginas normativas definen requisitos; las informativas ofrecen orientación. Los ejemplos son informativos. JSON se codifica en UTF-8 y los nombres de campo usan `snake_case`. ## 1.6 Terminología {#terminology} | Término | Significado | | --- | --- | | Servicio | Un proceso residente que implementa LMSP y ejecuta modelos mediante adaptadores. | | Cliente | Software que descubre e invoca un servicio: un agente, una aplicación o una herramienta. | | Adaptador | El componente que conecta el servicio con un único entorno de ejecución de modelos, como llama.cpp, Ollama o vLLM. | | Modelo | Un modelo disponible localmente, identificado por un `id` estable. | | Respuesta | El resultado de una solicitud de generación: elementos de salida, uso y un estado. | | Tarea | Una ejecución asíncrona y persistida de una solicitud de respuesta, con un estado explícito. | | Evento | Un evento enviado por el servidor, con número de secuencia, emitido mientras se genera una respuesta. | --- # Transporte y despliegue > Direcciones de escucha por defecto, transporte, formato de streaming y estructura de URL de un servicio LMSP, y cómo se ejecuta como servicio del sistema operativo, separado de los procesos de modelo. Source: https://madeforagent.com/es/lmsp/1.0/transport/ Language: es Specification: LMSP 1.0 (draft) Updated: 2026-11-08 ## 2.1 Despliegue por defecto {#deployment} Un servicio **DEBE** escuchar por defecto en las direcciones loopback `127.0.0.1` y `::1`. El puerto convencional es `17832`, lo que fija la dirección base por defecto en `http://127.0.0.1:17832`. | Elemento | Valor | | --- | --- | | Direcciones de escucha | `127.0.0.1` y `::1` | | Transporte | HTTP/1.1 o HTTP/2 con JSON | | Streaming | Eventos enviados por el servidor, `Content-Type: text/event-stream` | | Prefijo de la interfaz principal | `/lmsp/v1` | | Prefijo compatible con OpenAI | `/v1` | | Descripción del servicio | `GET /.well-known/lmsp.json` | | Contrato legible por máquina | `GET /lmsp/v1/openapi.json` | | Canal local opcional | Socket de dominio Unix o canal con nombre de Windows | Las solicitudes y las respuestas usan JSON en UTF-8 (`Content-Type: application/json`), salvo los flujos (`text/event-stream`) y los errores (`application/problem+json`). Las marcas de tiempo son enteros: segundos desde la época Unix. Los identificadores son cadenas opacas; un prefijo de tipo como `resp_` o `task_` es **RECOMENDADO**. El contrato de la interfaz es un documento OpenAPI 3.2. OpenAPI 3.2 puede describir eventos enviados por el servidor, JSON Lines y JSON Sequences, de modo que los endpoints de streaming se especifican en el mismo documento que el resto. El contrato de esta versión se publica en [`/lmsp/1.0/openapi.json`](https://madeforagent.com/lmsp/1.0/openapi.json). Un servicio **PUEDE** aceptar también conexiones en un socket de dominio Unix o en un canal con nombre de Windows con la misma semántica HTTP. En 1.0, la forma de anunciar esos endpoints se deja a las extensiones. ## 2.2 Funcionamiento permanente {#operation} Un servicio **DEBERÍA** ser alojado por el sistema operativo: launchd en macOS, systemd en Linux y el administrador de servicios en Windows. El proceso del servicio y los procesos de modelo **DEBERÍAN** estar separados. Un fallo de un modelo **DEBERÍA** afectar solo a las tareas que usan ese modelo. **NO DEBERÍA** dejar sin disponibilidad el descubrimiento del servicio, el catálogo de modelos ni las consultas sobre tareas anteriores. --- # Descubrimiento de servicios > Cómo los clientes LMSP encuentran un servicio local mediante configuración manual, sondeo de loopback y mDNS/DNS-SD opcional, y cómo leer el documento de descripción del servicio en la dirección conocida. Source: https://madeforagent.com/es/lmsp/1.0/discovery/ Language: es Specification: LMSP 1.0 (draft) Updated: 2026-11-08 ## 3.1 Métodos de descubrimiento {#methods} Un cliente descubre un servicio probando estos métodos por orden: 1. **Configuración manual.** El usuario introduce directamente la dirección del servicio. 2. **Sondeo de direcciones locales convencionales.** El cliente solicita `/.well-known/lmsp.json` a las direcciones candidatas. Las candidatas convencionales son `http://127.0.0.1:17832` y `http://[::1]:17832`. 3. **Descubrimiento en la LAN.** El cliente explora `_lmsp._tcp.local.` con mDNS y DNS-SD. Un método tiene éxito cuando produce una descripción de servicio válida ([sección 3.3](https://madeforagent.com/es/lmsp/1.0/discovery.md#service-description)). Una dirección que el usuario haya introducido manualmente siempre tiene prioridad sobre las descubiertas. ## 3.2 Anuncio en la LAN {#mdns} DNS-SD usa registros PTR para encontrar instancias de servicio, registros SRV para obtener el host y el puerto, y registros TXT para transportar una pequeña cantidad de información adicional. Combinado con mDNS, ofrece descubrimiento sin configuración en una red local ([RFC 6763](https://www.rfc-editor.org/rfc/rfc6763), [RFC 6762](https://www.rfc-editor.org/rfc/rfc6762)). Un ejemplo de anuncio: ```text Service type: _lmsp._tcp.local. Instance name: Workstation LMSP._lmsp._tcp.local. TXT record: v=1 id=svc_01J8M4Y8K6M5E6K6Z7Z0Y8W3M2 path=/ auth=pairing ``` | Clave TXT | Significado | | --- | --- | | `v` | Versión del formato del anuncio. `1` para LMSP 1.0. | | `id` | El id del servicio, igual a `service.id` en la descripción del servicio. | | `path` | Ruta URL de la raíz del servicio. Los clientes solicitan `{path}.well-known/lmsp.json`. | | `auth` | Indicación de autenticación. `pairing` significa que un cliente debe emparejarse antes de usar el servicio. | Reglas: - Un servicio **NO DEBE** poner tokens de acceso, listas de modelos, rutas de archivos ni ninguna otra información sensible en el registro TXT. El registro solo localiza el servicio. Las capacidades reales **DEBEN** leerse de la descripción del servicio. - Un servicio **DEBE** mantener desactivado por defecto el anuncio mDNS. Solo se activa cuando el usuario habilita explícitamente el descubrimiento en la LAN. Un servicio que se usa solo en la máquina local no se anuncia. - Un servicio que se anuncia en la LAN tiene que escuchar más allá de loopback, algo que solo se permite en modo LAN ([sección 10.5](https://madeforagent.com/es/lmsp/1.0/security.md#lan)). - Un cliente **DEBE** tratar el registro TXT como una pista sin verificar, y confirmar el servicio leyendo su descripción. ## 3.3 Descripción del servicio {#service-description} ```http GET /.well-known/lmsp.json ``` Un servicio **DEBE** servir este documento como `application/json` sin exigir autenticación. ```json { "protocol": "lmsp", "versions": ["1.0"], "service": { "id": "svc_01J8M4Y8K6M5E6K6Z7Z0Y8W3M2", "name": "Workstation Local Models", "version": "1.0.0" }, "interfaces": [ { "kind": "lmsp", "version": "1.0", "url": "http://127.0.0.1:17832/lmsp/v1", "transport": "http+json" }, { "kind": "openai", "version": "responses+chat", "url": "http://127.0.0.1:17832/v1", "transport": "http+json" } ], "capabilities": { "streaming": true, "tasks": true, "event_resume": true, "conversations": true, "model_management": true }, "authentication": { "type": "bearer", "pairing_url": "http://127.0.0.1:17832/lmsp/v1/pair" }, "openapi": "http://127.0.0.1:17832/lmsp/v1/openapi.json" } ``` | Campo | Significado | | --- | --- | | `protocol` | Siempre `"lmsp"`. | | `versions` | Las versiones de LMSP que admite el servicio, como cadenas `major.minor`. | | `service` | `id` es un identificador estable del servicio, `name` un nombre para mostrar y `version` la versión del software del servicio. | | `interfaces` | Las interfaces ofrecidas. Cada una tiene un `kind` (`lmsp`, `openai` u `ollama`), una `version`, una `url` base y un `transport`. Para `openai`, `version` nombra las familias de API servidas, como `responses+chat`. | | `capabilities` | Indicadores booleanos de funciones, enumerados a continuación. | | `authentication` | `type` es `bearer`. `pairing_url` es donde los clientes canjean un código de emparejamiento por un token ([sección 10.2](https://madeforagent.com/es/lmsp/1.0/security.md#pairing)). | | `openapi` | URL del documento OpenAPI que describe la interfaz LMSP. | Indicadores de capacidad: | Indicador | Significado | | --- | --- | | `streaming` | Las respuestas se pueden transmitir como eventos enviados por el servidor. **DEBE** ser `true` en 1.0. | | `tasks` | Hay tareas asíncronas disponibles. **DEBE** ser `true` en 1.0. | | `event_resume` | Los flujos de eventos de las tareas se pueden suscribir y reanudar (`GET /lmsp/v1/tasks/{task_id}/events`). | | `conversations` | El servicio almacena respuestas, por lo que `store` y `previous_response_id` funcionan y `GET /lmsp/v1/responses/{response_id}` está disponible. | | `model_management` | Los modelos se pueden cargar y liberar de la memoria de forma explícita. | ## 3.4 Comportamiento del cliente {#client-behavior} Un cliente: - **DEBERÍA** seleccionar la versión más alta de `versions` que también admita. - **DEBERÍA** seleccionar la interfaz LMSP o la interfaz OpenAI de `interfaces`, según lo que sepa hablar. - **DEBE** usar solo las capacidades que declara la descripción. Un indicador ausente significa `false`. - **DEBE** ignorar los campos de extensión que no reconozca. - **DEBERÍA** volver a leer la descripción del servicio periódicamente y cuando una solicitud falle, en lugar de conservarla en caché para siempre. - **DEBERÍA** recordar un servicio elegido por `service.id` y no por su dirección, porque las direcciones pueden cambiar. --- # Endpoints > La tabla completa de endpoints de LMSP 1.0 con método, ruta, nivel de exigencia y finalidad, además de las convenciones sobre rutas, autenticación y endpoints opcionales. Source: https://madeforagent.com/es/lmsp/1.0/endpoints/ Language: es Specification: LMSP 1.0 (draft) Updated: 2026-11-08 ## 4.1 Tabla de endpoints {#table} Un servicio conforme **DEBE** implementar todos los endpoints marcados como obligatorios. **PUEDE** implementar los opcionales, y los señala mediante los indicadores de capacidad de su [descripción del servicio](https://madeforagent.com/es/lmsp/1.0/discovery.md#service-description). | Método | Ruta | Exigencia | Finalidad | | --- | --- | --- | --- | | GET | `/.well-known/lmsp.json` | Obligatorio | [Descubrimiento del servicio y de sus capacidades](https://madeforagent.com/es/lmsp/1.0/discovery.md#service-description) | | GET | `/lmsp/v1/openapi.json` | Obligatorio | Especificación de la interfaz legible por máquina | | GET | `/lmsp/v1/health` | Obligatorio | [Comprobación de actividad y de preparación](https://madeforagent.com/es/lmsp/1.0/common-rules.md#health) | | POST | `/lmsp/v1/pair` | Obligatorio | [Canjear un código de emparejamiento por un token de portador](https://madeforagent.com/es/lmsp/1.0/security.md#pairing) | | GET | `/lmsp/v1/models` | Obligatorio | [Listar los modelos locales](https://madeforagent.com/es/lmsp/1.0/models.md#list) | | GET | `/lmsp/v1/models/{model_id}` | Obligatorio | [Obtener un modelo](https://madeforagent.com/es/lmsp/1.0/models.md#operations) | | POST | `/lmsp/v1/responses` | Obligatorio | [Generación síncrona o en streaming](https://madeforagent.com/es/lmsp/1.0/responses.md#request) | | GET | `/lmsp/v1/responses/{response_id}` | Opcional | [Recuperar una respuesta almacenada](https://madeforagent.com/es/lmsp/1.0/responses.md#sync) | | POST | `/lmsp/v1/tasks` | Obligatorio | [Crear una tarea de generación asíncrona](https://madeforagent.com/es/lmsp/1.0/tasks.md#create) | | GET | `/lmsp/v1/tasks/{task_id}` | Obligatorio | [Obtener una tarea asíncrona](https://madeforagent.com/es/lmsp/1.0/tasks.md#create) | | POST | `/lmsp/v1/tasks/{task_id}/cancel` | Obligatorio | [Cancelar una tarea asíncrona](https://madeforagent.com/es/lmsp/1.0/tasks.md#cancel) | | GET | `/lmsp/v1/tasks/{task_id}/events` | Opcional | [Suscribirse al flujo de eventos o reanudarlo](https://madeforagent.com/es/lmsp/1.0/tasks.md#events) | | POST | `/lmsp/v1/models/{model_id}/load` | Opcional | [Precargar un modelo](https://madeforagent.com/es/lmsp/1.0/models.md#operations) | | POST | `/lmsp/v1/models/{model_id}/unload` | Opcional | [Liberar un modelo de la memoria](https://madeforagent.com/es/lmsp/1.0/models.md#operations) | Los endpoints compatibles con OpenAI bajo `/v1` y los endpoints opcionales compatibles con Ollama se enumeran en la [página 8](https://madeforagent.com/es/lmsp/1.0/compatibility.md). ## 4.2 Convenciones {#conventions} - **Cuerpos.** Los cuerpos de las solicitudes y de las respuestas son JSON (`application/json`), salvo los flujos de eventos (`text/event-stream`) y los errores (`application/problem+json`). - **Parámetros de ruta.** Un nombre entre llaves, como `{model_id}`, es un marcador de posición. Los valores **DEBEN** codificarse con porcentaje. Un id de modelo como `qwen3:14b-q4_k_m` se envía como `qwen3%3A14b-q4_k_m`. - **Autenticación.** Todos los endpoints exigen `Authorization: Bearer `, salvo `/.well-known/lmsp.json`, `/lmsp/v1/openapi.json`, `/lmsp/v1/health` y `/lmsp/v1/pair`. - **Endpoints opcionales.** Un endpoint opcional que el servicio no implementa **DEBE** responder `501 Not Implemented` con el código de error `unsupported_capability`. - **Versiones y errores.** Las solicitudes pueden llevar cabeceras de versión, y todos los errores usan un mismo formato. Ambos se definen en la [página 9](https://madeforagent.com/es/lmsp/1.0/common-rules.md). - **Contrato.** El documento OpenAPI publicado en [`/lmsp/1.0/openapi.json`](https://madeforagent.com/lmsp/1.0/openapi.json) es la forma legible por máquina de esta página. El texto es normativo donde ambos difieran. --- # Catálogo de modelos > Cómo un servicio LMSP lista sus modelos locales, el objeto de modelo y sus indicadores de capacidad, los estados del ciclo de vida del modelo, los ids estables de modelo y las revisiones del catálogo. Source: https://madeforagent.com/es/lmsp/1.0/models/ Language: es Specification: LMSP 1.0 (draft) Updated: 2026-11-08 ## 5.1 Listar modelos {#list} ```http GET /lmsp/v1/models?capability=chat&ready_only=false Authorization: Bearer ``` | Parámetro de consulta | Significado | | --- | --- | | `capability` | Devuelve solo los modelos que tienen la capacidad indicada, por ejemplo `chat`, `embeddings` o `tools`. | | `ready_only` | Si es `true`, devuelve solo los modelos cuyo `status` es `ready`. Por defecto es `false`. | ```json { "object": "list", "catalog_revision": "42", "data": [ { "id": "qwen3:14b-q4_k_m", "object": "model", "display_name": "Qwen3 14B Q4_K_M", "owned_by": "local", "family": "qwen3", "revision": "sha256:8f27c1a4e9b05d36f2a7c8e1b4d90a63c5e2f7b8a1d4c9e60b3f5a7d2c8e1b04", "status": "ready", "capabilities": { "chat": true, "completion": true, "embeddings": false, "tools": true, "vision": false, "structured_output": true, "streaming": true }, "input_modalities": ["text"], "output_modalities": ["text"], "context_window": 32768, "max_output_tokens": 8192, "runtime": { "backend": "llama.cpp", "device": "metal", "load_on_demand": true } } ] } ``` Para que los clientes no tengan que obtener el catálogo completo una y otra vez, un servicio **DEBERÍA** devolver una cabecera `ETag`, un campo `catalog_revision`, o ambos: - `catalog_revision` es una cadena opaca que cambia cada vez que cambia el catálogo. - Un servicio que envía `ETag` **DEBERÍA** responder con `304 Not Modified` a un `If-None-Match` coincidente. ## 5.2 Objeto de modelo {#object} | Campo | Significado | | --- | --- | | `id` | Identificador estable del modelo, usado en toda solicitud que nombra un modelo. | | `object` | Siempre `"model"`. | | `display_name` | Nombre legible. El usuario puede cambiarlo. | | `aliases` | Lista opcional de nombres alternativos. Son solo informativos. | | `owned_by` | De dónde procede el modelo. `local` para los modelos instalados en este dispositivo. | | `family` | Familia del modelo, como `qwen3`. | | `revision` | Resumen criptográfico del contenido del modelo, como `sha256:8f27...`. | | `status` | Estado del ciclo de vida ([sección 5.3](https://madeforagent.com/es/lmsp/1.0/models.md#lifecycle)). | | `capabilities` | Indicadores booleanos: `chat`, `completion`, `embeddings`, `tools`, `vision`, `structured_output` y `streaming`. | | `input_modalities`, `output_modalities` | Los tipos de contenido que el modelo lee y escribe. `text` es la única modalidad definida en 1.0. | | `context_window` | Número máximo de tokens de contexto. | | `max_output_tokens` | Número máximo de tokens en una respuesta. | | `runtime` | `backend` (por ejemplo `llama.cpp`), `device` (por ejemplo `metal`) y `load_on_demand`. | | `error` | Presente cuando `status` es `error`. Un objeto de problema ([sección 9.3](https://madeforagent.com/es/lmsp/1.0/common-rules.md#errors)). | El `id` de un modelo **DEBE** ser estable. El usuario puede cambiar el nombre para mostrar y los alias, así que **NO DEBEN** usarse como clave primaria. ## 5.3 Ciclo de vida del modelo {#lifecycle} ```text installed --> loading --> ready --> unloading --> installed | +-----> error ``` | Estado | Significado | | --- | --- | | `installed` | El modelo existe pero no está cargado. | | `loading` | Se está asignando memoria o el entorno de ejecución se está inicializando. | | `ready` | El modelo puede procesar solicitudes de inmediato. | | `unloading` | Se están liberando recursos. | | `error` | La carga falló. El objeto de modelo **DEBERÍA** incluir un error estructurado. | Una nueva solicitud de carga devuelve a `loading` un modelo que está en estado `error`. Cuando una solicitud nombra un modelo que está `installed` y su `runtime.load_on_demand` es `true`, el servicio lo carga como parte de la solicitud. Si el modelo no puede usarse de inmediato y no se carga bajo demanda, el servicio responde `409` con `model_not_ready`. Si la carga falla, el error es `model_load_failed`. ## 5.4 Operaciones con modelos {#operations} `GET /lmsp/v1/models/{model_id}` devuelve un objeto de modelo. Un id desconocido produce `404` con `model_not_found`. Dos endpoints opcionales controlan la carga de forma explícita. Están disponibles cuando la capacidad `model_management` es `true`, y requieren el ámbito `models:manage` ([sección 10.3](https://madeforagent.com/es/lmsp/1.0/security.md#scopes)): | Endpoint | Comportamiento | | --- | --- | | `POST /lmsp/v1/models/{model_id}/load` | Precarga el modelo. Devuelve el objeto de modelo con `202 Accepted` cuando la carga ha comenzado, o `200` cuando ya está `ready`. | | `POST /lmsp/v1/models/{model_id}/unload` | Libera el modelo de la memoria. Devuelve el objeto de modelo. Repetir la solicitud es inocuo. | Ambos aceptan un `Idempotency-Key` ([sección 9.2](https://madeforagent.com/es/lmsp/1.0/common-rules.md#idempotency)). --- # Respuestas y streaming > La interfaz de conversación principal de LMSP, con solicitudes y elementos de salida al estilo Responses, generación síncrona y en streaming, eventos enviados por el servidor, reconexión y llamadas a herramientas. Source: https://madeforagent.com/es/lmsp/1.0/responses/ Language: es Specification: LMSP 1.0 (draft) Updated: 2026-11-08 ## 6.1 Solicitud {#request} ```http POST /lmsp/v1/responses Authorization: Bearer Content-Type: application/json Idempotency-Key: 01J8M5T7Z2K4N6Q8S0V3X5B9DG LMSP-Version: 1.0 ``` ```json { "model": "qwen3:14b-q4_k_m", "input": [ { "type": "message", "role": "user", "content": [ { "type": "input_text", "text": "Describe a local model service in one sentence." } ] } ], "stream": false, "max_output_tokens": 512, "temperature": 0.7, "response_format": { "type": "text" }, "store": true } ``` El protocolo principal usa una estructura `input` y `output` al estilo Responses en lugar de una simple lista de cadenas de mensajes, de modo que una única forma de solicitud pueda transportar: - mensajes de varios turnos; - texto, imágenes, audio y archivos; - llamadas a herramientas y resultados de herramientas; - salida estructurada; - resúmenes de razonamiento; - salida multimodal. LMSP 1.0 define solo contenido de texto. Los tipos de contenido de imagen, audio y archivo se reservan para versiones posteriores. | Campo | Obligatorio | Significado | | --- | --- | --- | | `model` | Sí | Id del modelo que se usará. | | `input` | Sí | Matriz de elementos de entrada. Un elemento `message` tiene un `role` (`system`, `user` o `assistant`) y una matriz `content` de partes, como `input_text`. El uso de herramientas añade los elementos `function_call` y `function_call_output` ([sección 6.5](https://madeforagent.com/es/lmsp/1.0/responses.md#tools)). | | `stream` | No | `true` para recibir eventos enviados por el servidor. Por defecto es `false`. | | `max_output_tokens` | No | Límite superior del número de tokens generados. | | `temperature` | No | Temperatura de muestreo. | | `response_format` | No | `{"type": "text"}` (el valor por defecto), o `{"type": "json_schema", "json_schema": {"name": "...", "schema": {...}}}` para salida estructurada. Requiere la capacidad `structured_output`. | | `tools`, `tool_choice` | No | Herramientas de función que el modelo puede invocar ([sección 6.5](https://madeforagent.com/es/lmsp/1.0/responses.md#tools)). Requiere la capacidad `tools`. | | `store` | No | Pide al servicio que conserve la respuesta, para poder recuperarla más tarde y usarla como `previous_response_id`. Por defecto es `false`. Los servicios sin la capacidad `conversations` lo ignoran. | | `previous_response_id` | No | Continúa desde una respuesta almacenada. Requiere la capacidad `conversations`. | | `extensions` | No | Extensiones privadas ([sección 9.1](https://madeforagent.com/es/lmsp/1.0/common-rules.md#versioning)). | Una solicitud que necesita una capacidad de la que el modelo carece se rechaza con `400` y `unsupported_capability`. Una solicitud que no cabe en la ventana de contexto se rechaza con `400` y `context_length_exceeded`. Un servicio que pueda almacenar conversaciones **PUEDE** admitir también `previous_response_id`. En caso contrario, cada solicitud **DEBE** llevar el contexto completo. Un servicio **NO DEBE** depender de la conexión HTTP para mantener el estado de la conversación. ## 6.2 Respuesta síncrona {#sync} Cuando `stream` es `false`, el servicio devuelve `200 OK` con un objeto de respuesta una vez terminada la generación. ```json { "id": "resp_01J8M6Q4W2T7N5R3V9X1Z8B0DF", "object": "response", "created_at": 1794200000, "status": "completed", "model": "qwen3:14b-q4_k_m", "output": [ { "id": "msg_01J8M6Q4W5C8H2K9P3S7Y1A6ZE", "type": "message", "role": "assistant", "content": [ { "type": "output_text", "text": "A local model service is a resident interface layer that discovers, manages and calls models on the user's own device." } ] } ], "usage": { "input_tokens": 28, "output_tokens": 31, "total_tokens": 59 }, "error": null, "incomplete_details": null } ``` | Campo | Significado | | --- | --- | | `id` | Identificador de la respuesta, como `resp_...`. | | `object` | Siempre `"response"`. | | `created_at` | Hora de creación, en segundos desde la época Unix. | | `status` | `in_progress`, `completed`, `incomplete`, `failed` o `cancelled`. Una respuesta síncrona se devuelve en un estado final. | | `model` | Id del modelo que produjo la respuesta. | | `output` | Matriz de elementos de salida. | | `usage` | Recuentos de tokens: `input_tokens`, `output_tokens` y `total_tokens`. | | `error` | `null`, o un objeto de problema ([sección 9.3](https://madeforagent.com/es/lmsp/1.0/common-rules.md#errors)) cuando `status` es `failed`. | | `incomplete_details` | `null`, o un objeto con un `reason` como `max_output_tokens` cuando `status` es `incomplete`. | Tipos de elemento de salida: | Tipo de elemento | Forma | | --- | --- | | `message` | `id`, `role` (`assistant`) y `content`, una matriz de partes `output_text` que tienen cada una un `text`. | | `function_call` | `id`, `call_id`, `name` y `arguments`, una cadena codificada en JSON. | | `reasoning` | `id` y `summary`, una matriz de partes `summary_text` que tienen cada una un `text`. | Si la generación falla, una solicitud síncrona recibe como respuesta un estado de error y un documento de problema ([sección 9.3](https://madeforagent.com/es/lmsp/1.0/common-rules.md#errors)), no un objeto de respuesta. El estado `failed` aparece en los flujos, las tareas y las respuestas almacenadas. `GET /lmsp/v1/responses/{response_id}` devuelve una respuesta que se almacenó con `store: true`. Es opcional y requiere la capacidad `conversations`. Un id desconocido produce `404` con `response_not_found`. ## 6.3 Streaming {#streaming} Para recibir la respuesta en streaming, establece `stream` en la solicitud: ```json { "stream": true } ``` El servicio responde `200 OK` con `Content-Type: text/event-stream` y envía eventos semánticos. Cada evento tiene un `id`, un nombre `event` y un objeto JSON `data`: ```text id: 1 event: response.created data: {"response_id":"resp_01J8M6Q4W2T7N5R3V9X1Z8B0DF","status":"in_progress"} id: 2 event: response.output_item.added data: {"response_id":"resp_01J8M6Q4W2T7N5R3V9X1Z8B0DF","output_index":0,"item":{"id":"msg_01J8M6Q4W5C8H2K9P3S7Y1A6ZE","type":"message","role":"assistant","content":[]}} id: 3 event: response.output_text.delta data: {"response_id":"resp_01J8M6Q4W2T7N5R3V9X1Z8B0DF","item_id":"msg_01J8M6Q4W5C8H2K9P3S7Y1A6ZE","delta":"A local model "} id: 4 event: response.output_text.delta data: {"response_id":"resp_01J8M6Q4W2T7N5R3V9X1Z8B0DF","item_id":"msg_01J8M6Q4W5C8H2K9P3S7Y1A6ZE","delta":"service is a resident interface layer."} id: 5 event: response.output_item.done data: {"response_id":"resp_01J8M6Q4W2T7N5R3V9X1Z8B0DF","output_index":0,"item":{"id":"msg_01J8M6Q4W5C8H2K9P3S7Y1A6ZE","type":"message","role":"assistant","content":[{"type":"output_text","text":"A local model service is a resident interface layer."}]}} id: 6 event: response.completed data: {"response_id":"resp_01J8M6Q4W2T7N5R3V9X1Z8B0DF","status":"completed","usage":{"input_tokens":28,"output_tokens":12,"total_tokens":40}} ``` Se definen al menos estos eventos: | Evento | Significado | Campos de datos | | --- | --- | --- | | `response.created` | Se creó la respuesta. | `response_id`, `status` (`in_progress`) | | `response.output_item.added` | Comenzó un nuevo elemento de salida. | `response_id`, `output_index`, `item` | | `response.output_text.delta` | Se añadió texto a un elemento de mensaje. | `response_id`, `item_id`, `delta` | | `response.output_item.done` | Un elemento de salida está completo. | `response_id`, `output_index`, `item` | | `response.completed` | La respuesta terminó. Evento final. | `response_id`, `status`, `usage` | | `response.incomplete` | La generación se detuvo antes de tiempo, por ejemplo al llegar al límite de tokens. Evento final. | `response_id`, `status`, `incomplete_details`, `usage` | | `response.failed` | La generación falló. Evento final. | `response_id`, `status`, `error` | | `response.cancelled` | Se canceló la respuesta. Evento final. | `response_id`, `status` | | `error` | Un problema no vinculado a una sola respuesta, tras el cual el flujo no puede continuar. | `error`, un objeto de problema | Un servicio cierra el flujo después de un evento final o de un evento `error`. Los servicios **PUEDEN** enviar eventos adicionales, por ejemplo para argumentos de llamadas a herramientas, imágenes, audio y deltas JSON estructurados. Los clientes **DEBEN** ignorar los tipos de evento que no conozcan. Si el cliente cierra la conexión de una solicitud en streaming, el servicio **DEBERÍA** dejar de generar. ## 6.4 Ids de evento y reconexión {#reconnection} El `id` de un evento **DEBE** ser un número de secuencia entero estrictamente creciente dentro de la respuesta, que empieza en 1. Tras una conexión interrumpida, un cliente reanuda enviando el último id que recibió. Lo hace con una cabecera: ```http Last-Event-ID: 2 ``` o con un parámetro de consulta: ```http GET /lmsp/v1/tasks/{task_id}/events?after=2 ``` Ambos van al endpoint de eventos de una tarea ([sección 7.4](https://madeforagent.com/es/lmsp/1.0/tasks.md#events)). El servicio reproduce solo los eventos cuyo número de secuencia es mayor que 2. Si están presentes los dos, prevalece `after`. Si los eventos solicitados son anteriores al período de retención, el servicio responde `410 Gone` con el error `event_history_expired`. El cliente obtiene entonces el resultado final con `GET /lmsp/v1/tasks/{task_id}`. Una respuesta transmitida directamente desde `POST /lmsp/v1/responses` pertenece a esa conexión HTTP y no se puede reanudar. Un cliente que necesite una salida reanudable **DEBERÍA** crear una [tarea](https://madeforagent.com/es/lmsp/1.0/tasks.md) y seguir sus eventos. ## 6.5 Llamadas a herramientas {#tools} LMSP 1.0 define herramientas de función que ejecuta el cliente. El servicio no ejecuta herramientas por sí mismo. El ámbito `tools:execute` se reserva para las extensiones que sí lo hacen ([sección 10.3](https://madeforagent.com/es/lmsp/1.0/security.md#scopes)). Primero, el cliente enumera las herramientas. Cada entrada tiene `type` con el valor `function`, un `name`, una `description` y `parameters`, un objeto JSON Schema. `tool_choice` es `auto` (el valor por defecto), `none`, `required` o `{"type": "function", "name": "get_weather"}`. ```json { "model": "qwen3:14b-q4_k_m", "input": [ { "type": "message", "role": "user", "content": [ { "type": "input_text", "text": "What is the weather in Hangzhou?" } ] } ], "tools": [ { "type": "function", "name": "get_weather", "description": "Get the current weather for a city.", "parameters": { "type": "object", "properties": { "city": { "type": "string" } }, "required": ["city"] } } ], "tool_choice": "auto" } ``` Cuando el modelo decide llamar a una herramienta, la respuesta contiene un elemento `function_call`. Sus `arguments` son una cadena codificada en JSON. En un flujo, el elemento llega completo en `response.output_item.done`. ```json { "id": "resp_01J8M7B3N6Q9T2V5X8Z1C4D7FH", "object": "response", "created_at": 1794200050, "status": "completed", "model": "qwen3:14b-q4_k_m", "output": [ { "id": "fc_01J8M7B3N8R1S4W7Y0A3E6G9JK", "type": "function_call", "call_id": "call_01J8M7B3N9T2V5X8Z1C4D7F0HM", "name": "get_weather", "arguments": "{\"city\":\"Hangzhou\"}" } ], "usage": { "input_tokens": 74, "output_tokens": 18, "total_tokens": 92 }, "error": null, "incomplete_details": null } ``` El cliente ejecuta la herramienta y luego envía una nueva solicitud que lleva el contexto completo: los elementos de entrada anteriores, el elemento `function_call` tal como se recibió y un elemento `function_call_output` con el mismo `call_id`. Su `output` es una cadena, normalmente codificada en JSON. ```json { "type": "function_call_output", "call_id": "call_01J8M7B3N9T2V5X8Z1C4D7F0HM", "output": "{\"temperature_c\":17,\"condition\":\"light rain\"}" } ``` --- # Tareas asíncronas > Cómo LMSP ejecuta generaciones largas como tareas persistentes, con creación de tareas, la máquina de estados de la tarea, cancelación idempotente, flujos de eventos y políticas de reinicio para las tareas sin terminar. Source: https://madeforagent.com/es/lmsp/1.0/tasks/ Language: es Specification: LMSP 1.0 (draft) Updated: 2026-11-08 ## 7.1 Crear una tarea {#create} Un cliente crea una tarea enviando por POST la solicitud de respuesta que quiere ejecutar, envuelta en un sobre de tarea. Se recomienda una cabecera `Idempotency-Key` ([sección 9.2](https://madeforagent.com/es/lmsp/1.0/common-rules.md#idempotency)). ```http POST /lmsp/v1/tasks Authorization: Bearer Idempotency-Key: 01J8M7C4Y3N5P8R2T6V9X1Z4BH ``` ```json { "type": "response", "input": { "model": "qwen3:14b-q4_k_m", "input": [ { "type": "message", "role": "user", "content": [ { "type": "input_text", "text": "Write a long report." } ] } ] }, "on_restart": "fail" } ``` | Campo | Obligatorio | Significado | | --- | --- | --- | | `type` | Sí | `response`, el único tipo de tarea en 1.0. | | `input` | Sí | Una solicitud de respuesta, exactamente igual que para `POST /lmsp/v1/responses`. Su campo `stream` se ignora. | | `on_restart` | No | `fail` (el valor por defecto), `retry` o `resume`. Consulta la [sección 7.5](https://madeforagent.com/es/lmsp/1.0/tasks.md#restart). | El servicio **DEBE** persistir la tarea antes de responder. Después devuelve: ```http HTTP/1.1 202 Accepted ``` ```json { "id": "task_01J8M8R5X3V7B2N4Q9T1W6Y0ZC", "object": "task", "type": "response", "status": "queued", "created_at": 1794200100, "updated_at": 1794200100, "response_id": "resp_01J8M8R5X4B9D2F6H1K3N7Q0ZW", "events_url": "/lmsp/v1/tasks/task_01J8M8R5X3V7B2N4Q9T1W6Y0ZC/events", "on_restart": "fail", "response": null, "error": null } ``` | Campo de la tarea | Significado | | --- | --- | | `id` | Identificador de la tarea, como `task_...`. | | `object` | Siempre `"task"`. | | `type` | `response`. | | `status` | El estado actual ([sección 7.2](https://madeforagent.com/es/lmsp/1.0/tasks.md#states)). | | `created_at`, `updated_at` | Horas en segundos desde la época Unix. | | `response_id` | Id de la respuesta que produce la tarea. Se asigna al crear la tarea. | | `events_url` | Ruta del flujo de eventos. Presente cuando la capacidad `event_resume` es `true`. | | `on_restart` | La política de reinicio de la tarea. | | `response` | El objeto de respuesta una vez que `status` es `succeeded`; en caso contrario, `null`. | | `error` | Un objeto de problema ([sección 9.3](https://madeforagent.com/es/lmsp/1.0/common-rules.md#errors)) cuando `status` es `failed`; en caso contrario, `null`. | `GET /lmsp/v1/tasks/{task_id}` devuelve el objeto de tarea. Los clientes que no usan flujos de eventos consultan periódicamente este endpoint. Un id desconocido produce `404` con `task_not_found`. Una tarea terminada tiene este aspecto: ```json { "id": "task_01J8M8R5X3V7B2N4Q9T1W6Y0ZC", "object": "task", "type": "response", "status": "succeeded", "created_at": 1794200100, "updated_at": 1794200162, "response_id": "resp_01J8M8R5X4B9D2F6H1K3N7Q0ZW", "events_url": "/lmsp/v1/tasks/task_01J8M8R5X3V7B2N4Q9T1W6Y0ZC/events", "on_restart": "fail", "response": { "id": "resp_01J8M8R5X4B9D2F6H1K3N7Q0ZW", "object": "response", "created_at": 1794200100, "status": "completed", "model": "qwen3:14b-q4_k_m", "output": [ { "id": "msg_01J8M8R6A2C5E8G1J4M7P0S3VY", "type": "message", "role": "assistant", "content": [ { "type": "output_text", "text": "Local model services make on-device inference a shared, discoverable utility..." } ] } ], "usage": { "input_tokens": 12, "output_tokens": 1480, "total_tokens": 1492 }, "error": null, "incomplete_details": null }, "error": null } ``` ## 7.2 Máquina de estados {#states} ```text queued --> loading --> running --> succeeded | | | | | +--> failed | | +--> cancelling --> cancelled | +--------------> failed +--------------------------> cancelled ``` | Estado | Significado | Estados siguientes | | --- | --- | --- | | `queued` | Aceptada y persistida, a la espera de empezar. | `loading`, `cancelled`, `failed` | | `loading` | Se está cargando el modelo. | `running`, `cancelling`, `failed` | | `running` | El modelo está generando. | `succeeded`, `failed`, `cancelling` | | `cancelling` | Se solicitó la cancelación y el backend aún no se ha detenido. | `cancelled` | | `succeeded` | Final. La respuesta está completa. | ninguno | | `failed` | Final. | ninguno | | `cancelled` | Final. | ninguno | Los estados terminales son `succeeded`, `failed` y `cancelled`. Una tarea en estado terminal **NO DEBE** volver a cambiar. Una tarea cuya respuesta termina como `incomplete`, por ejemplo al llegar al límite de tokens, está `succeeded`. Todas las transiciones son atómicas, así que una tarea nunca está a la vez cancelada y completada. Gana la transición que se confirme primero. ## 7.3 Cancelación {#cancel} ```http POST /lmsp/v1/tasks/{task_id}/cancel ``` El servicio devuelve `200 OK` y el objeto de tarea actual. Una tarea `queued` pasa a `cancelled` de inmediato. Una tarea `loading` o `running` pasa a `cancelling` hasta que el backend se haya detenido, y después a `cancelled`. La cancelación **DEBE** ser idempotente. Cancelar una tarea que ya está `cancelling` o `cancelled` devuelve la tarea actual y no produce ningún error nuevo. Cancelar una tarea que ya está `succeeded` o `failed` se responde con `409` y `task_not_cancelable`. Un id desconocido produce `404` con `task_not_found`. ## 7.4 Flujos de eventos {#events} ```http GET /lmsp/v1/tasks/{task_id}/events Accept: text/event-stream ``` Este endpoint es opcional. Está disponible cuando la capacidad `event_resume` es `true`. - Los eventos son los eventos de respuesta de la [sección 6.3](https://madeforagent.com/es/lmsp/1.0/responses.md#streaming), correspondientes a la respuesta que produce la tarea. La numeración y la reanudación siguen la [sección 6.4](https://madeforagent.com/es/lmsp/1.0/responses.md#reconnection). - El flujo empieza con `response.created`, que se registra cuando se acepta la tarea. Termina con un único evento final que corresponde al resultado: `response.completed`, `response.incomplete`, `response.failed` o `response.cancelled`. - Un cliente que se conecta tarde recibe primero los eventos que se perdió y después los eventos en vivo. El servicio cierra el flujo después del evento final. - Los eventos se conservan durante un período de retención ([sección 11.2](https://madeforagent.com/es/lmsp/1.0/persistence.md#rules)). Los eventos más antiguos producen `410 Gone` con `event_history_expired`. ## 7.5 Semántica de reinicio {#restart} `on_restart` indica qué ocurre con una tarea sin terminar cuando el servicio se reinicia: | Valor | Comportamiento | | --- | --- | | `fail` | El valor por defecto. El servicio marca la tarea sin terminar como `failed`, con el código de error `server_restarted`. | | `retry` | El servicio ejecuta la tarea de nuevo desde el principio. | | `resume` | El servicio continúa desde una instantánea. Esto solo se permite cuando el backend admite explícitamente instantáneas reanudables. En caso contrario, la solicitud de creación se rechaza con `400` y `unsupported_capability`. | Una tarea que está `cancelling` cuando el servicio se reinicia completa su cancelación y pasa a `cancelled`, sea cual sea su política. `retry` no se recomienda como valor por defecto, porque la tarea puede haber ejecutado ya herramientas o producido efectos secundarios externos. Un cliente que elige `retry` **DEBE** combinarlo con un `Idempotency-Key` y hacer que sus llamadas a herramientas sean idempotentes. --- # Compatibilidad con OpenAI y Ollama > Cómo un servicio LMSP sigue siendo compatible con los clientes OpenAI y Ollama existentes mediante una fina capa de conversión de datos sobre un único núcleo de ejecución, y dónde termina esa compatibilidad. Source: https://madeforagent.com/es/lmsp/1.0/compatibility/ Language: es Specification: LMSP 1.0 (draft) Updated: 2026-11-08 ## 8.1 Endpoints compatibles con OpenAI {#openai} Un servicio **DEBERÍA** ofrecer una interfaz compatible con OpenAI junto a la interfaz LMSP, y declararla en `interfaces` con `kind` establecido en `openai`. Para cubrir a los clientes existentes, un servicio que lo haga **DEBE** implementar al menos estos endpoints bajo el prefijo `/v1`: | Endpoint | Notas | | --- | --- | | `GET /v1/models` | Lista los modelos del catálogo LMSP. Cada `id` es el id de modelo de LMSP. | | `POST /v1/chat/completions` | Chat Completions, con y sin streaming. | | `POST /v1/responses` | La forma de OpenAI Responses. | | `POST /v1/embeddings` | La interfaz principal de LMSP 1.0 no tiene un endpoint de embeddings. El adaptador sirve este endpoint directamente, para los modelos cuyo `capabilities.embeddings` es `true`. | Estos endpoints aceptan los mismos tokens de portador que la interfaz LMSP. Un cliente que habla el protocolo OpenAI establece el token LMSP como su clave de API. Una primera implementación puede empezar con `/v1/models` y `/v1/chat/completions` ([página 12](https://madeforagent.com/es/lmsp/1.0/mvp.md)). ## 8.2 Endpoints compatibles con Ollama {#ollama} Un servicio **DEBERÍA** ofrecer también estos endpoints, para que funcionen igualmente los clientes escritos para Ollama: | Endpoint | Notas | | --- | --- | | `GET /api/tags` | Lista los modelos del catálogo LMSP. | | `POST /api/chat` | Chat. | | `POST /api/generate` | Generación de texto simple. | Un servicio que los ofrece declara una interfaz con `kind` establecido en `ollama`. ## 8.3 Un único núcleo de ejecución {#core} La capa de compatibilidad **DEBE** limitarse a convertir datos. **NO DEBE** crear un segundo conjunto de lógica de gestión de modelos. Una solicitud en una interfaz de compatibilidad se asigna a una respuesta LMSP, se ejecuta en el mismo núcleo y adaptador que una solicitud nativa, y usa el mismo catálogo de modelos y la misma autenticación. ```text OpenAI Chat Completions | asignación de la solicitud v LMSP Response | adaptación al backend v llama.cpp / Ollama / vLLM / otros entornos de ejecución ``` En los endpoints `/v1` y `/api`, un servicio **DEBERÍA** notificar los errores en el formato que define la API correspondiente, de modo que los clientes sin modificar puedan interpretarlos. La interfaz LMSP usa siempre `application/problem+json`. ## 8.4 Límites {#boundaries} La compatibilidad tiene límites, y conviene enunciarlos con claridad: - Un cliente compatible con OpenAI existente normalmente solo necesita cambiar su `base_url`. No obtiene automáticamente el descubrimiento de LMSP. - Solo los clientes que admiten LMSP pueden descubrir un servicio automáticamente, leer sus capacidades detalladas, reanudar flujos de eventos y gestionar tareas asíncronas. - Ningún protocolo del lado del servidor puede hacer que funcione un cliente que no se puede configurar y solo acepta direcciones oficiales en la nube. --- # Reglas comunes > Reglas compartidas por todos los endpoints de LMSP, con las cabeceras de versión y las extensiones, las claves de idempotencia, el formato de error problem+json y sus códigos, y la comprobación de estado. Source: https://madeforagent.com/es/lmsp/1.0/common-rules/ Language: es Specification: LMSP 1.0 (draft) Updated: 2026-11-08 ## 9.1 Versiones y extensiones {#versioning} Cada solicitud LMSP **PUEDE** llevar estas cabeceras: ```http LMSP-Version: 1.0 LMSP-Client: example-client/1.2.0 ``` `LMSP-Version` es la versión del protocolo a la que se dirige el cliente. `LMSP-Client` identifica el software cliente con fines de diagnóstico, como `name/version`. Un servicio **NO DEBE** cambiar el comportamiento del protocolo en función de esta última. Reglas: - La `v1` de la ruta indica la versión mayor. - Una solicitud que nombra una versión mayor desconocida se responde con `426 Upgrade Required` y el código de error `unsupported_protocol_version`. - Los nuevos campos opcionales **NO DEBEN** romper la compatibilidad 1.x. - Los servicios y los clientes **DEBEN** ignorar los campos que no conocen. - Las extensiones privadas van en un objeto `extensions` y se nombran con notación de dominio inverso: ```json { "extensions": { "com.example.cache": { "enabled": true } } } ``` ## 9.2 Idempotencia {#idempotency} Las solicitudes que crean algo, como crear una respuesta, crear una tarea o cargar un modelo, aceptan una clave de idempotencia: ```http Idempotency-Key: ``` El servicio almacena la clave junto con un resumen criptográfico del cuerpo de la solicitud y el resultado: - La misma clave con el mismo cuerpo devuelve el resultado original. - La misma clave con un cuerpo distinto se responde con `409 Conflict` y `idempotency_conflict`. Una clave se limita al cliente y al endpoint. **DEBERÍA** ser un valor único de como máximo 255 caracteres, como un ULID o un UUID. Un servicio **DEBERÍA** conservar las claves al menos 24 horas. Un servicio **PUEDE** ignorar la clave en las solicitudes en streaming. Un cliente que necesita reintentos seguros usa una [tarea](https://madeforagent.com/es/lmsp/1.0/tasks.md). ## 9.3 Errores {#errors} Todo error de la interfaz LMSP usa `application/problem+json` ([RFC 9457](https://www.rfc-editor.org/rfc/rfc9457)): ```json { "type": "urn:lmsp:error:model-not-found", "title": "Model not found", "status": 404, "code": "model_not_found", "detail": "No local model with id 'qwen3:14b-q4_k_m'", "request_id": "req_01J8M9S6Y4W8C3P5R1V7Z2A0DH", "retryable": false } ``` | Campo | Obligatorio | Significado | | --- | --- | --- | | `type` | Sí | URI que identifica el tipo de error. LMSP usa `urn:lmsp:error:` seguido del código con guiones en lugar de guiones bajos. | | `title` | Sí | Resumen breve y legible. | | `status` | Sí | El código de estado HTTP. | | `code` | Sí | Código de error legible por máquina, de la lista siguiente. | | `detail` | No | Explicación legible de esta ocurrencia. **NO DEBE** contener secretos, prompts ni contenido generado. | | `request_id` | No | Identificador de la solicitud, para correlacionarla con los registros del servicio. | | `retryable` | Sí | Si repetir la solicitud más tarde puede tener éxito. | Códigos de error habituales: | Código | Estado HTTP | Reintentable | Significado | | --- | --- | --- | --- | | `invalid_request` | 400 | No | La solicitud está mal formada o tiene parámetros no válidos. | | `unauthorized` | 401 | No | Falta el token, no es válido, ha caducado o se ha revocado, o un código de emparejamiento es incorrecto. | | `forbidden` | 403 | No | El token no tiene el ámbito necesario, o falló la comprobación de `Origin` o `Host`. | | `model_not_found` | 404 | No | Ningún modelo local tiene este id. | | `model_not_ready` | 409 | Sí | El modelo no está cargado y no se carga bajo demanda. | | `model_load_failed` | 500 | Sí | Falló la carga del modelo. | | `context_length_exceeded` | 400 | No | La entrada no cabe en la ventana de contexto del modelo. | | `unsupported_capability` | 400 o 501 | No | El modelo o el servicio no admite lo que necesita la solicitud. Un endpoint opcional no implementado responde 501. | | `unsupported_protocol_version` | 426 | No | El servicio no admite la versión mayor solicitada. | | `response_not_found` | 404 | No | Ninguna respuesta almacenada tiene este id. | | `task_not_found` | 404 | No | Ninguna tarea tiene este id. | | `task_not_cancelable` | 409 | No | La tarea ya ha terminado correctamente o con un fallo. | | `idempotency_conflict` | 409 | No | La clave de idempotencia ya se usó con un cuerpo de solicitud distinto. | | `event_history_expired` | 410 | No | Los eventos solicitados son anteriores al período de retención. | | `rate_limited` | 429 | Sí | Demasiadas solicitudes. | | `resource_exhausted` | 503 | Sí | Al dispositivo se le acabó la memoria u otro recurso. | | `backend_unavailable` | 503 | Sí | No se puede acceder al entorno de ejecución del modelo. | | `server_restarted` | 503 | Sí | El servicio se reinició mientras la tarea estaba sin terminar. | | `internal_error` | 500 | Varía | Un fallo inesperado dentro del servicio. | El campo `retryable` es el que prevalece. La columna anterior muestra el valor habitual. Un servicio **PUEDE** definir más códigos. Un cliente **DEBE** tratar un código que no conoce según su estado HTTP y su campo `retryable`. ## 9.4 Comprobación de estado {#health} ```http GET /lmsp/v1/health ``` ```json { "status": "ready", "service_id": "svc_01J8M4Y8K6M5E6K6Z7Z0Y8W3M2", "uptime_seconds": 86420, "loaded_models": 1, "active_tasks": 2, "storage": "ok" } ``` | Campo | Significado | | --- | --- | | `status` | `starting`, `ready`, `degraded` o `stopping`. | | `service_id` | El id del servicio de la descripción del servicio. | | `uptime_seconds` | Segundos desde que se inició el servicio. | | `loaded_models` | Número de modelos en estado `ready`. | | `active_tasks` | Número de tareas que están `queued`, `loading`, `running` o `cancelling`. | | `storage` | `ok` o `error`. | El estado HTTP es `200 OK` cuando `status` es `ready` o `degraded`, y `503 Service Unavailable` en caso contrario. El endpoint de estado devuelve solo el estado operativo. **NO DEBE** devolver rutas de modelos, prompts, tokens de acceso ni otra información sensible. --- # Seguridad local > Requisitos de seguridad para los servicios LMSP, con enlace a loopback, emparejamiento y tokens de portador, ámbitos, comprobaciones de Origin y Host frente a páginas web maliciosas, modo LAN y reglas de registro. Source: https://madeforagent.com/es/lmsp/1.0/security/ Language: es Specification: LMSP 1.0 (draft) Updated: 2026-11-08 ## 10.1 Línea base {#baseline} Escuchar solo en localhost no es seguridad absoluta: una página web maliciosa aún puede intentar acceder a los puertos locales. Por eso LMSP combina varias medidas. - Un servicio **DEBE** enlazarse por defecto a las direcciones loopback. **NO DEBE** escuchar en `0.0.0.0` ni en ninguna otra dirección que no sea loopback, salvo que el modo LAN esté activado ([sección 10.5](https://madeforagent.com/es/lmsp/1.0/security.md#lan)). - En la primera ejecución, un servicio **DEBERÍA** generar un secreto de servicio aleatorio de alta entropía y usarlo, en lugar de cualquier valor por defecto incorporado, para emitir y verificar tokens. - Toda solicitud a la interfaz principal **DEBE** llevar un token de portador válido, salvo los endpoints de arranque enumerados en la [sección 4.2](https://madeforagent.com/es/lmsp/1.0/endpoints.md#conventions). Provenir de loopback nunca basta por sí solo. ## 10.2 Emparejamiento y tokens {#pairing} Un cliente obtiene su propio token de portador con un código de emparejamiento local. El usuario pide al servicio que muestre un código de emparejamiento, del modo que el servicio ofrezca, y el cliente lo envía: ```http POST /lmsp/v1/pair Content-Type: application/json ``` ```json { "client_name": "example-client", "pairing_code": "K7QD-4M2X", "scopes": ["inference"] } ``` | Campo de la solicitud | Significado | | --- | --- | | `client_name` | Nombre para mostrar del cliente, que se muestra al usuario. | | `pairing_code` | El código que el usuario obtuvo del servicio. | | `scopes` | Lista opcional de ámbitos solicitados. Por defecto es `["inference"]`. | El servicio responde con un token. El `token_type` es siempre `Bearer`: ```json { "client_id": "cli_01J8MAT3W6X9B2D5F8H1K4N7QZ", "access_token": "lmsp_example_3f9a1c52e7d84b60", "token_type": "Bearer", "scopes": ["inference"] } ``` Después, el cliente envía `Authorization: Bearer ` con cada solicitud. - Un código de emparejamiento **DEBE** ser de un solo uso y **DEBERÍA** caducar en un plazo de 5 minutos. **DEBERÍA** tener al menos 40 bits de entropía. Un servicio **DEBE** limitar la frecuencia de los intentos fallidos. Un código incorrecto o caducado se responde con `401` y `unauthorized`. - Los tokens son independientes para cada cliente, de modo que el usuario puede revocar uno sin afectar a los demás. Un servicio **DEBERÍA** permitir al usuario listar y revocar los clientes emparejados. - Un cliente **DEBERÍA** guardar su token en el llavero o en el administrador de credenciales del sistema operativo. Un servicio **DEBERÍA** almacenar solo un hash de cada token. - Un token ausente, no válido o revocado se responde con `401`, `unauthorized` y una cabecera `WWW-Authenticate: Bearer`. Un token válido que carece del ámbito que necesita un endpoint se responde con `403` y `forbidden`. ## 10.3 Ámbitos {#scopes} Los permisos se dividen en ámbitos distintos. Descargar modelos, eliminar modelos y ejecutar herramientas nunca viajan con el ámbito de inferencia. | Ámbito | Permite | | --- | --- | | `inference` | Leer el catálogo de modelos, crear respuestas y tareas, y leer y cancelar las tareas del propio cliente. | | `models:manage` | Cargar y liberar modelos de la memoria. | | `models:install` | Reservado. Descargar y eliminar modelos. | | `tools:execute` | Reservado. Ejecutar herramientas en el lado del servicio. | Las tareas y las respuestas almacenadas pertenecen al cliente que las creó. Un servicio **DEBERÍA** responder a la solicitud de otro cliente como si no existieran (`task_not_found` o `response_not_found`). ## 10.4 Protecciones del navegador y de la red {#browser} - Un servicio **DEBE** rechazar por defecto las solicitudes de navegador de origen cruzado, y permitir solo los valores de `Origin` configurados explícitamente. Una solicitud con cualquier otro `Origin` se responde con `403` y `forbidden`. - Cuando se permite un origen, el servicio responde a sus solicitudes previas CORS y envía `Access-Control-Allow-Origin` con ese origen exacto, nunca con `*`. - Un servicio **DEBE** validar la cabecera `Host`, para evitar el DNS rebinding. Solo acepta los nombres de host que sirve: los nombres y direcciones loopback, más los nombres configurados para el modo LAN. Cualquier otro valor se responde con `403` y `forbidden`. ## 10.5 Modo LAN {#lan} El modo LAN significa escuchar más allá de las direcciones loopback. - Un servicio **NO DEBE** activar el modo LAN salvo que el usuario lo habilite explícitamente. - En modo LAN, un servicio **DEBE** exigir autenticación y **DEBERÍA** activar también TLS. Un cliente **NO DEBERÍA** enviar un token por HTTP sin cifrar a una dirección que no sea loopback, salvo que el usuario lo permita explícitamente. - El anuncio mDNS solo se permite en modo LAN, cuando el usuario ha activado además el descubrimiento en la LAN ([sección 3.2](https://madeforagent.com/es/lmsp/1.0/discovery.md#mdns)). ## 10.6 Registro y privacidad {#logging} - Las rutas de modelos, los registros, los prompts y el contenido generado **NO DEBEN** aparecer en los anuncios mDNS. - Por defecto, un servicio **DEBERÍA** registrar solo metadatos (horas, endpoints, códigos de estado, ids, recuentos de tokens y duraciones). **NO DEBERÍA** registrar prompts completos ni contenido generado. - Las respuestas de estado y los detalles de error **NO DEBEN** contener rutas de modelos, prompts, tokens de acceso ni otra información sensible. --- # Persistencia > Cómo un servicio LMSP almacena su estado, con una base de datos SQLite integrada, las tablas que conservar, las reglas transaccionales para tareas y eventos, la retención y la recuperación al arrancar. Source: https://madeforagent.com/es/lmsp/1.0/persistence/ Language: es Specification: LMSP 1.0 (draft) Updated: 2026-11-08 ## 11.1 Almacenamiento {#storage} Un servicio **DEBERÍA** guardar su estado en una base de datos [SQLite](https://www.sqlite.org/) integrada. Un conjunto de tablas sugerido: | Tabla | Contenido | | --- | --- | | `service_config` | Identidad y configuración del servicio. | | `clients` | Clientes emparejados, hashes de tokens y ámbitos. | | `models` | Metadatos de los modelos y resúmenes criptográficos de su contenido. | | `responses` | Respuestas almacenadas. | | `tasks` | Tareas asíncronas. | | `task_events` | El registro de eventos de cada tarea, con números de secuencia. | | `idempotency_keys` | Claves de idempotencia, resúmenes de solicitudes y resultados. | Los archivos de modelo **DEBEN** quedar fuera de la base de datos. La base de datos contiene solo metadatos y resúmenes criptográficos del contenido. Los nombres y la disposición de las tablas son una decisión de implementación. Lo que los clientes pueden observar, y lo que tiene que ser interoperable, es el comportamiento descrito en las dos secciones siguientes. ## 11.2 Reglas {#rules} Sea cual sea el almacenamiento que use un servicio, este: - **DEBE** persistir una tarea antes de devolver `202 Accepted`. - **DEBE** actualizar los números de secuencia de los eventos y el estado de la tarea en la misma transacción. - **DEBE** hacer atómica la transición de cancelación, para evitar la condición de carrera de una tarea que se cancela y luego se completa. - **DEBERÍA** conservar las tareas y los eventos terminados durante un período de retención configurable. - **NO DEBE** eliminar tareas sin terminar durante la limpieza de registros. - **DEBE**, al arrancar, examinar las tareas `queued`, `loading`, `running` y `cancelling` que hayan quedado, y aplicar la política de reinicio de cada una ([sección 7.5](https://madeforagent.com/es/lmsp/1.0/tasks.md#restart)). ## 11.3 Recuperación al arrancar {#recovery} La tabla muestra el estado al que pasa una tarea que quedó pendiente, según su política `on_restart`: | Estado encontrado al arrancar | `fail` | `retry` | `resume` | | --- | --- | --- | --- | | `queued` | `failed` | `queued` | `queued` | | `loading` | `failed` | `queued` | `queued` | | `running` | `failed` | `queued` | `running`, continuando desde la instantánea | | `cancelling` | `cancelled` | `cancelled` | `cancelled` | Una tarea que pasa a `failed` recibe el código de error `server_restarted` y un evento `response.failed`. Una tarea que pasa a `cancelled` recibe un evento `response.cancelled`. El nuevo estado y su evento se escriben en una sola transacción ([sección 11.2](https://madeforagent.com/es/lmsp/1.0/persistence.md#rules)). --- # Alcance mínimo viable > Un alcance sugerido para una primera implementación de LMSP, con las diez piezas que forman un circuito cerrado utilizable y las partes de la especificación que pueden esperar a versiones posteriores. Source: https://madeforagent.com/es/lmsp/1.0/mvp/ Language: es Specification: LMSP 1.0 (draft) Updated: 2026-11-08 ## 12.1 Primera versión {#scope} La primera versión no tiene que implementar todas las funciones multimodales, la descarga de modelos ni la voz en tiempo real. Forma un circuito cerrado utilizable en cuanto ofrece: 1. Descubrimiento del servicio mediante `/.well-known/lmsp.json`. 2. Anuncio opcional en la LAN de `_lmsp._tcp.local.`. 3. `GET /lmsp/v1/models`. 4. `POST /lmsp/v1/responses`, tanto síncrono como en un flujo SSE. 5. Tareas asíncronas: crear, consultar y cancelar, con persistencia en SQLite. 6. Reanudación de los flujos interrumpidos con `Last-Event-ID` o `after`. 7. Tokens de portador, emparejamiento local y protección de `Origin` y `Host`. 8. Los endpoints `/v1/models` y `/v1/chat/completions` compatibles con OpenAI. 9. Un archivo de contrato OpenAPI 3.2 y pruebas de conformidad entre lenguajes. 10. Al menos un backend real y una comprobación de que las tareas se recuperan correctamente tras reiniciar el servicio. El sentido de este diseño: LMSP aporta el conjunto completo de capacidades, la interfaz de OpenAI aporta compatibilidad lista para usar, mDNS y la descripción del servicio aportan descubrimiento automático, y el modelo de tareas en SQLite aporta persistencia local. ## 12.2 Lo que puede esperar {#later} Todo lo que la lista anterior no menciona puede llegar en versiones posteriores. Esto incluye los endpoints opcionales (respuestas almacenadas, y carga y liberación de modelos), los endpoints `/v1/responses` y `/v1/embeddings` de OpenAI, la API compatible con Ollama y todos los tipos de contenido que no sean texto. Este alcance es un camino hacia una primera versión utilizable, no un perfil de conformidad. Un servicio que afirma ser compatible con LMSP 1.0 sigue implementando todos los endpoints obligatorios de la [página 4](https://madeforagent.com/es/lmsp/1.0/endpoints.md) y el comportamiento obligatorio descrito en las demás páginas.