Referencia de la API
ollaya serve expone dos API en http://localhost:11435:
- la API nativa bajo
/api/*, inspirada en la de Ollama, para decisiones y gestión de modelos; - la API compatible con TypeSafe bajo
/v1/*, idéntica a nivel de cable a la de TypeSafe, para que los SDK de TypeSafe existentes funcionen sin cambios. Consulta Compatibilidad con TypeSafe.
| Método | Ruta | Propósito |
|---|---|---|
GET, HEAD |
/ |
Comprobación de vida (liveness): Ollaya is running |
GET |
/api/version |
Versión del servidor |
POST |
/api/decide |
Responde preguntas tipadas sobre un estado; también carga y descarga de la memoria un modelo |
GET |
/api/tags |
Modelos de esta máquina |
POST |
/api/show |
Detalles de un modelo |
GET |
/api/ps |
Modelos cargados en memoria |
POST |
/api/pull |
Descarga un modelo (transmite el progreso) |
DELETE |
/api/delete |
Elimina un modelo |
POST |
/api/copy |
Copia un modelo a un nombre nuevo |
POST |
/api/create |
Crea un modelo a partir de otro (transmite el progreso) |
POST |
/v1/systemone |
TypeSafe System One |
POST |
/v1/decisions |
Alias de /v1/systemone |
GET |
/v1/models |
Lista de modelos de TypeSafe |
/api/push y /api/blobs/:digest están reservados y responden 501 NOT_IMPLEMENTED. Los endpoints de texto de Ollama (/api/generate, /api/chat, /api/embed) responden 404: los modelos de decisión nunca generan texto.
Convenciones
- JSON. Los cuerpos de solicitud y respuesta son objetos JSON. El cuerpo se analiza como JSON sea cual sea su
Content-Type, así quecurl -dfunciona tal cual. Las solicitudes son de 8 MiB como máximo. - Nombres de campos en
snake_case. Los campos de solicitud desconocidos se ignoran;nullsignifica ausente. - Nombres de modelos con la forma
[host/][namespace/]model[:tag], sin distinguir mayúsculas de minúsculas. Una etiqueta ausente significalatest. Las respuestas siempre usan la forma canónica, comolaya:latest. - Números. Las probabilidades, las confianzas,
scoreynoulse redondean a 4 decimales. Las duraciones son enteros en nanosegundos; las marcas de tiempo son RFC 3339 en UTC. - Streaming.
/api/pully/api/createtransmiten JSON delimitado por saltos de línea, un objeto por línea, y terminan con exactamente un{"status":"success"}o una línea de error. Envía"stream": falsepara una sola respuesta. - IDs de solicitud. Cada respuesta lleva
X-Request-Id, y las de/v1/*tambiénx-typesafe-request-id. UnX-Request-Idválido enviado por el cliente se devuelve tal cual. - Concurrencia. Un modelo cargado ejecuta una solicitud a la vez, y cada solicitud responde todas sus preguntas en una sola pasada. Las solicitudes a un mismo modelo se ponen en cola, así que enviar más a la vez no termina antes; el viaje de ida y vuelta de cada una incluye entonces la espera. Haz todas las preguntas sobre un estado en una sola solicitud. Los distintos modelos cargados se ejecutan en paralelo.
- Sin descargas implícitas. Ningún endpoint descarga un modelo como efecto secundario.
ollaya rundescarga primero; las aplicaciones llaman a/api/pull.
Errores
Cada error, en cada endpoint, tiene este cuerpo:
{
"error": "model \"laya:xl\" not found, try pulling it first",
"code": "MODEL_NOT_FOUND"
}
| Campo | Significado |
|---|---|
error |
Mensaje legible por humanos. No lo analices; el único mensaje congelado es model "<name>" not found, try pulling it first, como en Ollama. |
code |
Código legible por máquinas. Ramifica según este. |
detail |
Solo para INVALID_REQUEST, TOO_MANY_OPTIONS, INPUT_TOO_LONG y STATE_TRUNCATED: cada problema de validación, con la forma ValidationError de TypeSafe (FastAPI): loc, msg, type y a veces ctx. |
| Código | HTTP | Cuándo | Reintento |
|---|---|---|---|
INVALID_JSON |
400 | Falta el cuerpo, no es JSON o no es un objeto | no |
INVALID_REQUEST |
422 | El cuerpo no pasa la validación; detail enumera cada problema |
no |
TOO_MANY_OPTIONS |
422 | Las opciones de una pregunta no caben en el presupuesto de opciones del modelo | no |
INPUT_TOO_LONG |
422 | state supera los 65,536 tokens |
no |
STATE_TRUNCATED |
422 | /v1/systemone o /v1/decisions descartaría parte de state para caber en el contexto del modelo |
no |
UNAUTHORIZED |
401 | OLLAYA_API_KEY está definida y la solicitud no lleva la clave |
no |
FORBIDDEN |
403 | La cabecera Origin o Host del navegador no está permitida |
no |
MODEL_NOT_FOUND |
404 | El modelo (o el objetivo de un router) no está en esta máquina; en una descarga, no está en el registro | no |
NOT_FOUND |
404 | No existe tal endpoint | no |
METHOD_NOT_ALLOWED |
405 | El endpoint existe, el método no | no |
OPERATION_IN_PROGRESS |
409 | Una descarga o una creación está escribiendo el mismo nombre de modelo | después de que termine |
REQUEST_TOO_LARGE |
413 | El cuerpo supera los 8 MiB | no |
QUEUE_FULL |
503 | Ya hay OLLAYA_MAX_QUEUE solicitudes esperando; se envía con Retry-After: 1 |
sí |
MODEL_LOAD_FAILED |
500 | El modelo no se pudo cargar (archivos corruptos, memoria, OLLAYA_LOAD_TIMEOUT) |
rara vez |
INFERENCE_FAILED |
500 | El runner falló durante una decisión | sí |
STORAGE_ERROR |
500 | Disco lleno, permisos o E/S | no |
INTERNAL |
500 | Un bug; el registro del servidor tiene los detalles bajo el ID de solicitud | sí |
UNSUPPORTED_MODEL |
501 | Esta compilación no puede ejecutar el formato del modelo | no |
NOT_IMPLEMENTED |
501 | Endpoint reservado | no |
REGISTRY_ERROR |
502 | El registro no está accesible o no es válido | sí |
DIGEST_MISMATCH |
502 | Una descarga no coincidió con su sha256 y se descartó | sí |
El conjunto de códigos es abierto: trata un código desconocido según su estado HTTP. Un error de validación enumera todos los problemas a la vez:
{
"error": "state: Field required; questions.urgency.score.criteria: List should have at least 2 items after validation, not 1",
"code": "INVALID_REQUEST",
"detail": [
{"loc": ["body", "state"], "msg": "Field required", "type": "missing"},
{
"loc": ["body", "questions", "urgency", "score", "criteria"],
"msg": "List should have at least 2 items after validation, not 1",
"type": "too_short",
"ctx": {"field_type": "List", "min_length": 2, "actual_length": 1}
}
]
}
Una vez que ha empezado un stream, un fallo llega como una última línea con la misma forma, como {"error": "…", "code": "DIGEST_MISMATCH"}. Comprueba en cada línea el campo error antes de leerla como progreso.
Preguntas
/api/decide, /v1/systemone y /api/create comparten un único esquema de preguntas, el de TypeSafe. Una solicitud tiene 1–256 preguntas, indexadas por cualquier id; las respuestas vuelven en el mismo orden.
type |
instructions |
criteria |
Respuesta |
|---|---|---|---|
choice |
opcional | obligatorio: etiqueta de objeto → descripción, o un array de etiquetas; 2–255 opciones | choice, confidence, probabilities |
score |
opcional | obligatorio: array de descripciones de nivel, el nivel 0 primero; 2–10 niveles | score, confidence, legend, probabilities |
noul |
opcional | opcional: {"true": "…", "false": "…"} |
noul |
instructionspuede ser una cadena, un objeto, un array onull. Cuando falta o esnull, el modelo lee en su lugar el id de la pregunta, así que un id descriptivo comois_spamfunciona por sí solo.statees una cadena, un objeto o un array, de hasta 65,536 tokens. Si supera el contexto disponible del modelo,/api/decidelo trunca e informastate_truncated: true./v1/systemoney/v1/decisionsdevuelven422 STATE_TRUNCATEDcon el modelo que respondió endetail[0].ctx.model.- Límites del modelo. Cada opción necesita sitio en el contexto del modelo: unas 125 opciones para
laya:en(512 tokens) y 250 paralaya:multilingual(1,024). Más es422 TOO_MANY_OPTIONS. Para un router, se aplican los límites del objetivo.
Las respuestas son las formas de TypeSafe, en este orden de campos:
type |
Campos |
|---|---|
choice |
choice: la etiqueta más probable. confidence. probabilities: etiqueta → probabilidad, en el orden de los criterios. |
score |
score: el nivel esperado Σ i·pᵢ, que puede caer entre niveles. confidence. legend: "0"… → la descripción del nivel. probabilities: "0"… → probabilidad. |
noul |
noul: la probabilidad de que la afirmación se cumpla. Sin confidence, como en TypeSafe. |
confidence es la probabilidad superior normalizada de TypeSafe, (K · pmax − 1) / (K − 1) para K opciones: 0 cuando todas las opciones son igual de probables, 1 cuando una opción tiene toda la probabilidad. La fórmula es la misma para todos los modelos, pero lo que significa una confianza dada no lo es: los modelos están calibrados de forma distinta, así que ajusta un umbral por modelo con tus propios datos. Las probabilidades se calibran con las temperaturas de cada modelo. En una GPU CUDA se ejecuta el grafo fp16, cuyas respuestas pueden diferir de las de fp32 en empates ajustados.
keep_alive
Cuánto tiempo permanece cargado un modelo después de que termina una solicitud, con la semántica de Ollama:
| Valor | Significado |
|---|---|
"5m", "1h30m", "300ms", 300, "300" |
Permanece cargado ese tiempo tras la solicitud |
0, "0", "0s" |
Se descarga de la memoria en cuanto termina la solicitud |
-1, "-5m", cualquier valor negativo |
Permanece cargado hasta que el servidor se detiene o hasta una descarga de memoria explícita |
ausente o null |
OLLAYA_KEEP_ALIVE, por defecto 5m |
El temporizador arranca cuando termina una solicitud, y gana el valor de la solicitud más reciente. Para un router, se aplica al objetivo que respondió. /v1/* ignora keep_alive.
Decide
POST /api/decide
Responde preguntas tipadas sobre un estado en una sola pasada hacia adelante. El cuerpo es el de /v1/systemone más opciones nativas; la respuesta es la de TypeSafe más campos nativos, así que un cliente de TypeSafe también puede analizarla.
| Campo | Tipo | Obligatorio | Notas |
|---|---|---|---|
model |
string | sí | Nombre del modelo |
state |
string, object or array | sí para decidir | Sin él, la solicitud carga o descarga de la memoria el modelo (abajo) |
questions |
object | sí, salvo que el modelo tenga preguntas integradas | Sustituye por completo las preguntas propias del modelo |
preset |
string | no | Nombre de un preajuste, integrado o personalizado, en lugar de questions |
images |
array of strings | no | Para un modelo de visión: imágenes PNG, en base64 o URLs data: en base64. Decider admite una; winnow:e4b-vision admite hasta 16. Consulta Imágenes |
keep_alive |
string or number | no | Consulta keep_alive |
extras |
array of strings | no | ["laya"] añade a cada respuesta la confianza propia de laya y la probabilidad de acto |
stream |
boolean | no | Reservado; true se rechaza |
curl http://localhost:11435/api/decide -d '{
"model": "laya",
"state": "I was charged twice for my subscription this month. Please refund the second charge.",
"questions": {
"department": {
"type": "choice",
"instructions": "Which team should handle this ticket?",
"criteria": {
"billing": "Payments, invoices and refunds",
"technical": "Bugs, errors and outages",
"account": "Login, profile and settings"
}
},
"urgency": {
"type": "score",
"instructions": "How urgent is this ticket?",
"criteria": ["Can wait", "Needs attention this week", "Needs attention today"]
},
"refund": {
"type": "noul",
"instructions": "The customer asks for money back.",
"criteria": {"true": "Asks for a refund", "false": "Does not ask for a refund"}
}
},
"keep_alive": "10m"
}'
{
"model": "laya:en",
"answers": {
"department": {
"type": "choice",
"choice": "billing",
"confidence": 0.7781,
"probabilities": {"billing": 0.8521, "technical": 0.0611, "account": 0.0868}
},
"urgency": {
"type": "score",
"score": 1.1982,
"confidence": 0.3418,
"legend": {"0": "Can wait", "1": "Needs attention this week", "2": "Needs attention today"},
"probabilities": {"0": 0.1203, "1": 0.5612, "2": 0.3185}
},
"refund": {"type": "noul", "noul": 0.9127}
},
"usage": {"input_tokens": 118, "output_tokens": 0},
"routing": {
"router": "laya:latest",
"model": "laya:en",
"route": "english",
"reason": "English Latin text"
},
"state_truncated": false,
"done_reason": "decide",
"created_at": "2026-09-24T09:30:12.418Z",
"total_duration": 18734512,
"load_duration": 0,
"eval_duration": 16302117
}
| Campo | Significado |
|---|---|
model |
El modelo que respondió: para un router, su objetivo (laya:en para una solicitud laya) |
answers |
id de pregunta → respuesta, en el orden de las preguntas |
usage |
input_tokens leídos; output_tokens siempre es 0 |
routing |
Para un router: router, el model elegido, una clave route estable y un reason informativo. null en caso contrario. |
state_truncated |
true si se descartó parte del estado para caber en el contexto del modelo |
done_reason |
"decide", "load" o "unload" |
created_at |
Cuándo se produjo la respuesta |
total_duration |
Nanosegundos desde que se recibe la solicitud hasta la respuesta, incluida la cola |
load_duration |
Nanosegundos esperando a que se cargue el modelo; 0 cuando ya estaba caliente |
eval_duration |
Nanosegundos en el runner: tokenización, pasada hacia adelante, calibración |
Con "extras": ["laya"], cada respuesta tiene además un objeto laya: confidence (la confianza de laya basada en la entropía) y act_probability (de la cabeza de acto del modelo, o null).
Imágenes
Un modelo de visión (decider:2b-vision o winnow:e4b-vision) responde preguntas sobre una imagen además de sobre el estado. Envía la imagen en images, codificada en base64, igual que funciona el images de Ollama:
curl http://localhost:11435/api/decide -d '{
"model": "decider:2b-vision",
"state": "A photo from the warehouse camera.",
"images": ["'"$(base64 -w0 shelf.png)"'"],
"questions": {
"blocked": {"type": "noul", "instructions": "Is the aisle blocked?"},
"fill": {"type": "score", "instructions": "How full is the shelf?", "criteria": ["empty", "half full", "full"]}
}
}'
- Decider: Una imagen por solicitud, solo PNG. El preprocesamiento del modelo se reproduce valor por valor, así que los píxeles tienen que coincidir con lo que decodifican los autores del modelo. Los decodificadores JPEG de Rust difieren de libjpeg-turbo en hasta 4 niveles en algunos píxeles, así que JPEG aún no se acepta: conviértelo antes a PNG.
- Decider: La imagen se redimensiona a múltiplos de 32 píxeles, como espera el modelo, y después puede tener como máximo 4,096 parches de 16x16 píxeles, alrededor de un megapíxel (1024x1024). Una imagen más grande recibe un 422 que lo dice; redúcela primero.
- Decider: Las preguntas admiten como máximo 10 opciones. El mismo modelo también responde solicitudes solo de texto.
- Winnow E4B vision: hasta 16 PNG ordenados, 2–64 opciones por pregunta, dentro del contexto combinado de imagen/estado/pregunta. El proyector correspondiente se descarga por separado de la misma revisión del autor. Las etiquetas de texto existentes de Winnow no lo cargan.
- Un modelo que no lee imágenes responde a una solicitud con
imagescon un 422.
/v1/systemone y /v1/decisions siguen siendo idénticos a la API de TypeSafe, que no tiene campo de imagen.
Carga y descarga de la memoria. Una solicitud sin state ni questions nunca decide. Sin keep_alive, o con uno positivo o negativo, carga el modelo (cada objetivo, para un router) y devuelve done_reason: "load". Con keep_alive: 0 lo descarga de la memoria ("unload"). ollaya run precarga de esta forma, y ollaya stop descarga de la memoria.
curl http://localhost:11435/api/decide -d '{"model": "laya:en", "keep_alive": -1}'
curl http://localhost:11435/api/decide -d '{"model": "laya:en", "keep_alive": 0}'
Una decisión no tiene efecto secundario sobre los datos almacenados, así que es seguro reintentarla.
Preajustes
Un preajuste es un conjunto de preguntas con nombre. Hay seis integrados (triage, email, guard, moderation, router, agent), y puedes guardar los tuyos. Envía "preset": "NAME" a /api/decide en lugar de questions.
curl http://localhost:11435/api/presets/create -d '{
"name": "billing-check",
"description": "Billing, and how upset the customer is",
"questions": {
"billing": {"type": "noul", "instructions": "The message is about a charge, an invoice or a refund."},
"tone": {"type": "choice", "instructions": "How does the customer sound?", "criteria": {"calm": null, "annoyed": null, "angry": null}}
}
}'
curl http://localhost:11435/api/decide -d '{"model": "winnow:e4b", "state": "I was charged twice this month.", "preset": "billing-check"}'
| Endpoint | Cuerpo | Efecto |
|---|---|---|
GET /api/presets |
– | Preajustes integrados primero, luego los personalizados: name, builtin, description, ids de pregunta, modified_at |
POST /api/presets/create |
name, questions, description (opcional) |
Guarda un preajuste personalizado, reemplazando el que tenga el mismo nombre |
POST /api/presets/show |
name |
Un preajuste con sus preguntas |
DELETE /api/presets/delete |
name |
Elimina un preajuste personalizado |
Los nombres tienen de 1 a 64 caracteres de letras minúsculas, dígitos, - y _. Un nombre integrado no se puede reutilizar (422) ni eliminar (403), y un nombre desconocido es un 404. Los preajustes personalizados se guardan junto a los modelos, así que cada cliente del servidor ve los mismos.
Routers
Un router como laya (laya:latest) no tiene pesos: en cada solicitud elige uno de sus objetivos, que es el que responde. laya solo lee state:
| Estado | route |
Responde |
|---|---|---|
| Inglés | english |
laya:en |
| Mayormente escritura no latina (árabe, cirílica, CJK, …) | multilingual |
laya:multilingual |
| Escritura latina, pero no inglés (turco, alemán, …) | multilingual |
laya:multilingual |
| Sin letras | english (el valor por defecto) |
laya:en |
Texto corto en mayúsculas y sin letras acentuadas, como nombres de comercios en un extracto de tarjeta (MIGROS KADIKOY ISTANBUL TR), SKUs o nombres de usuario, por lo general no se puede identificar y va a laya:en. Si conoces el idioma, pide laya:multilingual o laya:en directamente; el model de la respuesta dice qué checkpoint respondió.
El enrutamiento cuesta microsegundos. Ramifica según route, nunca según reason, cuya redacción puede cambiar. laya:typed-decisions nunca lo elige el router; pídelo directamente.
Listar los modelos locales
GET /api/tags
Los modelos de esta máquina, los más recientes primero. Cada entrada tiene name, model (el mismo), modified_at, size en bytes, digest (sha256 del manifiesto, en hexadecimal sin prefijo) y details: parent_model, format (onnx, gguf o router), family, families, parameter_size y quantization_level (las precisiones que lleva, como F16/F32, o la cuantización de un modelo GGUF, como Q8_0).
{
"models": [
{
"name": "laya:en",
"model": "laya:en",
"modified_at": "2026-09-24T08:11:02.117Z",
"size": 853634822,
"digest": "bf30e4654e9483ff1e6a4fe6fb21b8a71baff6c8a01013046e7d13339020efd7",
"details": {
"parent_model": "",
"format": "onnx",
"family": "laya",
"families": ["laya"],
"parameter_size": "421M",
"quantization_level": "F16/F32"
}
}
]
}
Mostrar los detalles de un modelo
POST /api/show
curl http://localhost:11435/api/show -d '{"model": "laya:en"}'
| Campo | Significado |
|---|---|
license |
Texto de la licencia |
modelfile |
Un Modelfile que recrea el modelo |
parameters |
Parámetros definidos en el modelo, un name value por línea, como precision fp32 |
questions |
Preguntas integradas, o null |
router |
Para un router: strategy, default y routes (route → model). null en caso contrario. |
details |
Como en /api/tags |
model_info |
general.architecture, general.languages, general.source (el repositorio fijo de Hugging Face), más claves propias de la familia como laya.context_length. general.languages enumera los idiomas para los que se entrenó y evaluó el modelo (multilingual en muchos casos); un modelo construido sobre una base multilingüe puede leer aún otros idiomas, así que mide con tus datos. |
capabilities |
Tipos de pregunta que responde (choice, score, noul), más act si tiene cabeza de acto |
modified_at |
Como en /api/tags |
Un router se muestra como él mismo, sin resolverse a un objetivo.
Listar los modelos en ejecución
GET /api/ps
Los modelos cargados, ordenados por nombre. Los routers nunca aparecen; sus objetivos cargados sí. Cada entrada tiene name, model, size (memoria, RAM más VRAM), digest, details (con la precisión cargada realmente: F16 o F32, o la cuantización de un modelo GGUF), expires_at (cuándo se descargará de la memoria, o null cuando se mantiene cargado), size_vram, context_length y device (cpu, cuda:0, metal, …).
Descargar un modelo
POST /api/pull
{"model": "laya:en"}
Descarga el modelo al almacén local y verifica cada blob contra su sha256. Descargar un router descarga también cada modelo al que enruta. Solo se descargan las capas que necesita esta máquina, los blobs compartidos entre modelos se descargan una vez, y las descargas interrumpidas se reanudan.
La respuesta transmite el progreso, con las cadenas de estado de Ollama:
{"status":"pulling manifest"}
{"status":"pulling 891102d37268","digest":"sha256:891102d372688fc2a094dac56a384bc537b87c63f21f9f3dac0be2b7cbc8d86c","total":842609210,"completed":420557117}
{"status":"pulling 891102d37268","digest":"sha256:891102d372688fc2a094dac56a384bc537b87c63f21f9f3dac0be2b7cbc8d86c","total":842609210,"completed":842609210}
{"status":"verifying sha256 digest"}
{"status":"writing manifest"}
{"status":"success"}
Un modelo solo aparece en /api/tags después de writing manifest. Para un router hay un único success, al final del todo. Un nombre que no se puede analizar, un modelo que no está en el registro y un registro inaccesible son errores HTTP normales (422, 404, 502) antes de que empiece el stream, así que curl --fail funciona. Con "stream": false la respuesta es {"status": "success"} cuando termina. Una segunda descarga del mismo nombre se une a la que está en curso. Es seguro reintentar.
Eliminar un modelo
DELETE /api/delete
{"model": "triage"}
Elimina el nombre, y los blobs que no usa ningún otro modelo. Un modelo cargado se descarga de la memoria cuando terminan sus solicitudes; eliminar un router conserva sus objetivos. La respuesta es 200 con cuerpo vacío, y 404 MODEL_NOT_FOUND cuando el nombre no existe; tras un timeout, trátalo como éxito.
Copiar un modelo
POST /api/copy
{"source": "laya:en", "destination": "my-guardrail"}
Copia un modelo a un nombre nuevo, sobrescribiendo un destino existente. La respuesta es 200 con cuerpo vacío.
Crear un modelo
POST /api/create
La API que hay detrás de ollaya create -f Modelfile: la CLI lee el Modelfile y los archivos que menciona y envía sus contenidos como JSON.
| Campo | Tipo | Obligatorio | Notas |
|---|---|---|---|
model |
string | sí | Nombre que crear |
from |
string | sí | Un modelo local, posiblemente un router. Nunca se descarga. |
questions |
object | no | Preguntas integradas, validadas como una solicitud de decisión |
calibration |
object | no | temperature: hasta 3 números (choice, score, noul). temperature_by_options: "<type>:<2|3-5|6-10|11+>" → number. |
parameters |
object | no | precision: "fp16" o "fp32", para fijar un grafo |
license |
string or array | no | Texto(s) de licencia |
description |
string | no | Una línea, mostrada por /v1/models y ollaya show |
stream |
boolean | no | Por defecto true |
curl http://localhost:11435/api/create -d '{
"model": "triage",
"from": "laya:en",
"questions": {
"department": {
"type": "choice",
"instructions": "Which team should handle this ticket?",
"criteria": ["billing", "technical", "account"]
}
},
"parameters": {"precision": "fp32"},
"description": "Support ticket triage"
}'
El stream informa using existing layer sha256:… por cada capa heredada, creating new layer sha256:… por cada capa nueva, y luego writing manifest y success. Las capas están direccionadas por contenido, así que repetir una creación da el mismo modelo.
Versión
GET /api/version
{"version": "0.1.0"}
Endpoints compatibles con TypeSafe
| Endpoint | Descripción |
|---|---|
POST /v1/systemone |
Solicitud: model, state (obligatorio) y questions. Respuesta: exactamente model, answers y usage. |
POST /v1/decisions |
Alias de /v1/systemone |
GET /v1/models |
Los modelos locales, como {"models": [{"name", "description", "release_date"}]} |
/v1/* ignora campos nativos como keep_alive y extras, y nunca añade campos nativos a sus respuestas. Los errores usan el mismo cuerpo que /api/*, que el SDK de TypeSafe lee correctamente. Consulta Compatibilidad con TypeSafe.
Seguridad
El servidor se enlaza a 127.0.0.1:11435 y, como Ollama, confía en los llamadores locales. Enlazarlo a otra dirección (OLLAYA_HOST=0.0.0.0) permite que todo el que pueda alcanzar el puerto ejecute decisiones y descargue, elimine y cree modelos, así que:
OLLAYA_API_KEYhace que cada solicitud salvoGET /,HEAD /y el preflight CORS requieraAuthorization: Bearer <key>; de lo contrario la respuesta es401 UNAUTHORIZED. El SDK de TypeSafe envía su clave así, y la CLIollayaenvía$OLLAYA_API_KEY. El servidor registra un aviso cuando escucha más allá de loopback sin una clave.- TLS no lo termina el servidor; pon un proxy inverso delante para el acceso remoto.
- Navegadores. Las solicitudes con una cabecera
Originsolo se permiten desdelocalhost,127.0.0.1,0.0.0.0y[::1](cualquier puerto), los webviews de aplicaciones y editores, y los orígenes enOLLAYA_ORIGINS(separados por comas, con comodines*). Un servidor en loopback también rechaza cabecerasHostinesperadas, lo que bloquea el DNS rebinding. - Tus datos. Los estados y las preguntas nunca se registran ni se repiten en los errores.
| Variable | Por defecto | Efecto |
|---|---|---|
OLLAYA_HOST |
127.0.0.1:11435 |
Dirección de enlace; el objetivo del cliente. Una dirección de loopback también escucha en [::1], así que los programas de Windows alcanzan sin demora un servidor en WSL en localhost |
OLLAYA_API_KEY |
sin definir | Exige Authorization: Bearer <key> |
OLLAYA_ORIGINS |
sin definir | Orígenes de navegador permitidos adicionales |
OLLAYA_KEEP_ALIVE |
5m |
keep_alive por defecto |
OLLAYA_MAX_LOADED_MODELS |
3 |
Límite de modelos cargados |
OLLAYA_MAX_QUEUE |
512 |
Solicitudes en curso antes de 503 QUEUE_FULL |
OLLAYA_LOAD_TIMEOUT |
5m |
Plazo de carga antes de 500 MODEL_LOAD_FAILED |
OLLAYA_DEVICE |
auto |
auto, cpu, cuda o cuda:<n> |
OLLAYA_MODELS |
~/.ollaya/models |
Almacén de modelos |
OLLAYA_REGISTRY |
ollaya.dev |
Host de registro por defecto en los nombres |