Documentation

Référence de l'API

ollaya serve expose deux API sur http://localhost:11435 :

  • l’API native sous /api/*, calquée sur celle d’Ollama, pour les décisions et la gestion des modèles ;
  • l’API compatible TypeSafe sous /v1/*, identique sur le fil à celle de TypeSafe, pour que les SDK TypeSafe existants fonctionnent sans modification. Voir Compatibilité TypeSafe.
Méthode Chemin Rôle
GET, HEAD / Sonde de vie (liveness) : Ollaya is running
GET /api/version Version du serveur
POST /api/decide Répond à des questions typées sur un état ; charge et décharge aussi un modèle
GET /api/tags Modèles présents sur cette machine
POST /api/show Détails d’un modèle
GET /api/ps Modèles chargés en mémoire
POST /api/pull Télécharge un modèle (diffuse la progression)
DELETE /api/delete Supprime un modèle
POST /api/copy Copie un modèle sous un nouveau nom
POST /api/create Crée un modèle à partir d’un autre (diffuse la progression)
POST /v1/systemone TypeSafe System One
POST /v1/decisions Alias de /v1/systemone
GET /v1/models Liste des modèles TypeSafe

/api/push et /api/blobs/:digest sont réservés et répondent 501 NOT_IMPLEMENTED. Les endpoints de texte d’Ollama (/api/generate, /api/chat, /api/embed) répondent 404 : les modèles de décision ne génèrent jamais de texte.

Conventions

  • JSON. Les corps de requête et de réponse sont des objets JSON. Le corps est analysé comme du JSON quel que soit son Content-Type, donc curl -d fonctionne tel quel. Les requêtes font au plus 8 MiB.
  • Noms de champs. Ils sont en snake_case. Les champs de requête inconnus sont ignorés ; null signifie absent.
  • Noms de modèles. Ils sont [host/][namespace/]model[:tag], insensibles à la casse. Un tag absent signifie latest. Les réponses utilisent toujours la forme canonique, comme laya:latest.
  • Nombres. Les probabilités, les confiances, le score et le noul sont arrondis à 4 décimales. Les durées sont des entiers en nanosecondes ; les horodatages sont en RFC 3339 en UTC.
  • Streaming. /api/pull et /api/create diffusent du JSON délimité par des retours à la ligne, un objet par ligne, en terminant par exactement un {"status":"success"} ou une ligne d’erreur. Envoie "stream": false pour une réponse unique.
  • IDs de requête. Chaque réponse porte X-Request-Id, et les réponses /v1/* aussi x-typesafe-request-id. Un X-Request-Id valide envoyé par le client est renvoyé tel quel.
  • Concurrence. Un modèle chargé traite une requête à la fois, et chaque requête répond à toutes ses questions en une passe. Les requêtes vers le même modèle font la queue, donc en envoyer plus d’un coup ne finit pas plus tôt ; le temps aller-retour de chacune inclut alors l’attente. Pose toutes les questions sur un état en une seule requête. Les différents modèles chargés tournent en parallèle.
  • Pas de téléchargement implicite. Aucun endpoint ne télécharge un modèle en effet de bord. ollaya run télécharge d’abord ; les applications appellent /api/pull.

Erreurs

Chaque erreur, sur chaque endpoint, a ce corps :

{
  "error": "model \"laya:xl\" not found, try pulling it first",
  "code": "MODEL_NOT_FOUND"
}
Champ Signification
error Message lisible par un humain. Ne l’analyse pas ; le seul message figé est model "<name>" not found, try pulling it first, comme dans Ollama.
code Code lisible par une machine. Branche sur celui-ci.
detail Uniquement pour INVALID_REQUEST, TOO_MANY_OPTIONS, INPUT_TOO_LONG et STATE_TRUNCATED : chaque problème de validation, dans la forme ValidationError de TypeSafe (FastAPI) : loc, msg, type et parfois ctx.
Code HTTP Quand Nouvelle tentative
INVALID_JSON 400 Corps manquant, non JSON, ou pas un objet non
INVALID_REQUEST 422 Le corps échoue à la validation ; detail liste chaque problème non
TOO_MANY_OPTIONS 422 Les options d’une question ne tiennent pas dans le budget d’options du modèle non
INPUT_TOO_LONG 422 state dépasse 65 536 jetons non
STATE_TRUNCATED 422 /v1/systemone ou /v1/decisions écarterait une partie de state pour tenir dans le contexte du modèle non
UNAUTHORIZED 401 OLLAYA_API_KEY est définie et la requête n’a pas la clé non
FORBIDDEN 403 En-tête Origin ou Host du navigateur non autorisé non
MODEL_NOT_FOUND 404 Modèle (ou cible d’un routeur) absent de cette machine ; pour un téléchargement, absent du registre non
NOT_FOUND 404 Cet endpoint n’existe pas non
METHOD_NOT_ALLOWED 405 L’endpoint existe, la méthode non non
OPERATION_IN_PROGRESS 409 Un téléchargement ou une création écrit le même nom de modèle après sa fin
REQUEST_TOO_LARGE 413 Corps supérieur à 8 MiB non
QUEUE_FULL 503 OLLAYA_MAX_QUEUE requêtes déjà en attente ; envoyé avec Retry-After: 1 oui
MODEL_LOAD_FAILED 500 Le modèle n’a pas pu se charger (fichiers corrompus, mémoire, OLLAYA_LOAD_TIMEOUT) rarement
INFERENCE_FAILED 500 Le moteur a échoué pendant une décision oui
STORAGE_ERROR 500 Disque plein, permissions ou E/S non
INTERNAL 500 Un bug ; le journal du serveur a les détails sous l’ID de requête oui
UNSUPPORTED_MODEL 501 Cette compilation ne sait pas exécuter le format du modèle non
NOT_IMPLEMENTED 501 Endpoint réservé non
REGISTRY_ERROR 502 Registre injoignable ou invalide oui
DIGEST_MISMATCH 502 Un téléchargement ne correspondait pas à son sha256 et a été écarté oui

L’ensemble des codes est ouvert : traite un code inconnu selon son statut HTTP. Une erreur de validation liste tous les problèmes d’un coup :

{
  "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}
    }
  ]
}

Une fois qu’un flux a démarré, une panne arrive en dernière ligne sous la même forme, comme {"error": "…", "code": "DIGEST_MISMATCH"}. Vérifie la présence de error sur chaque ligne avant de la lire comme une progression.

Questions

/api/decide, /v1/systemone et /api/create partagent un même schéma de questions, celui de TypeSafe. Une requête a 1–256 questions, indexées par n’importe quel id ; les réponses reviennent dans le même ordre.

type instructions criteria Réponse
choice facultatif requis : objet libellé → description, ou un tableau de libellés ; options 2–255 choice, confidence, probabilities
score facultatif requis : tableau de descriptions de niveaux, niveau 0 en premier ; 2–10 niveaux score, confidence, legend, probabilities
noul facultatif facultatif : {"true": "…", "false": "…"} noul
  • instructions peut être une chaîne, un objet, un tableau ou null. Quand il est absent ou null, le modèle lit à la place l’id de la question, donc un id descriptif comme is_spam suffit à lui seul.
  • state est une chaîne, un objet ou un tableau, jusqu’à 65 536 jetons. S’il dépasse le contexte disponible du modèle, /api/decide le tronque et rapporte state_truncated: true. /v1/systemone et /v1/decisions renvoient 422 STATE_TRUNCATED avec le modèle qui a répondu dans detail[0].ctx.model.
  • Limites du modèle. Chaque option a besoin de place dans le contexte du modèle : environ 125 options pour laya:en (512 jetons) et 250 pour laya:multilingual (1 024). Au-delà, c’est 422 TOO_MANY_OPTIONS. Pour un routeur, ce sont les limites de la cible qui s’appliquent.

Les réponses sont les formes de TypeSafe, dans cet ordre de champs :

type Champs
choice choice : le libellé le plus probable. confidence. probabilities : libellé → probabilité, dans l’ordre des criteria.
score score : le niveau attendu Σ i·pᵢ, qui peut tomber entre les niveaux. confidence. legend : "0"… → la description du niveau. probabilities : "0"… → probabilité.
noul noul : la probabilité que l’affirmation soit vraie. Pas de confidence, comme dans TypeSafe.

confidence est la probabilité maximale normalisée de TypeSafe, (K · pmax − 1) / (K − 1) pour K options : 0 quand toutes les options sont également probables, 1 quand une option a toute la probabilité. La formule est la même pour tous les modèles, mais ce que signifie une confiance donnée ne l’est pas : les modèles sont calibrés différemment, donc règle un seuil par modèle sur tes propres données. Les probabilités sont calibrées avec les températures de chaque modèle. Sur un GPU CUDA, le graphe fp16 s’exécute, et ses réponses peuvent différer du fp32 sur les quasi-égalités.

keep_alive

Combien de temps un modèle reste chargé après la fin d’une requête, avec la sémantique d’Ollama :

Valeur Signification
"5m", "1h30m", "300ms", 300, "300" Reste chargé ce laps de temps après la requête
0, "0", "0s" Décharge dès que la requête se termine
-1, "-5m", toute valeur négative Reste chargé jusqu’à l’arrêt du serveur ou un déchargement explicite
absent ou null OLLAYA_KEEP_ALIVE, par défaut 5m

Le minuteur démarre à la fin d’une requête, et la valeur de la dernière requête l’emporte. Pour un routeur, il s’applique à la cible qui a répondu. /v1/* ignore keep_alive.

Décide

POST /api/decide

Répond à des questions typées sur un état en une seule passe avant. Le corps est celui de /v1/systemone plus des options natives ; la réponse est celle de TypeSafe plus des champs natifs, donc un client TypeSafe peut aussi la lire.

Champ Type Requis Remarques
model string oui Nom du modèle
state string, object or array oui pour décider Sans lui, la requête charge ou décharge le modèle (ci-dessous)
questions object oui, sauf si le modèle a des questions intégrées Remplace entièrement les questions propres du modèle
preset string non Nom d’un préréglage, intégré ou personnalisé, à la place de questions
images array of strings non Pour un modèle de vision : des images PNG, en base64 ou des URL data: en base64. Decider en prend une ; winnow:e4b-vision en prend jusqu’à 16. Voir Images
keep_alive string or number non Voir keep_alive
extras array of strings non ["laya"] ajoute la confiance propre de laya et sa probabilité d’acte à chaque réponse
stream boolean non Réservé ; true est refusé
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
}
Champ Signification
model Le modèle qui a répondu : pour un routeur, sa cible (laya:en pour une requête laya)
answers Id de question → réponse, dans l’ordre des questions
usage input_tokens lus ; output_tokens vaut toujours 0
routing Pour un routeur : router, le model choisi, une clé route stable et un reason informatif. null sinon.
state_truncated true si une partie de l’état a été écartée pour tenir dans le contexte du modèle
done_reason "decide", "load" ou "unload"
created_at Quand la réponse a été produite
total_duration Nanosecondes entre la réception de la requête et la réponse, mise en file comprise
load_duration Nanosecondes passées à attendre le chargement du modèle ; 0 quand il était chaud
eval_duration Nanosecondes dans le moteur : tokenisation, passe avant, calibration

Avec "extras": ["laya"], chaque réponse a aussi un objet laya : confidence (la confiance de laya fondée sur l’entropie) et act_probability (issue de la tête d’acte du modèle, ou null).

Images

Un modèle de vision (decider:2b-vision ou winnow:e4b-vision) répond à des questions sur une image comme sur l’état. Envoie l’image dans images, encodée en base64, comme fonctionne images d’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: Une image par requête, PNG uniquement. Le prétraitement du modèle est reproduit valeur pour valeur, donc les pixels doivent correspondre à ce que décodent les auteurs du modèle. Les décodeurs JPEG de Rust diffèrent de libjpeg-turbo jusqu’à 4 niveaux sur certains pixels, donc le JPEG n’est pas encore accepté : convertis-le d’abord en PNG.
  • Decider: L’image est redimensionnée en multiples de 32 pixels, comme l’attend le modèle, et peut avoir au plus 4 096 patchs de 16x16 pixels ensuite, environ un mégapixel (1024x1024). Une image plus grande reçoit un 422 qui le dit ; réduis-la d’abord.
  • Decider: Les questions prennent au plus 10 options. Le même modèle répond aussi aux requêtes textuelles seules.
  • Winnow E4B vision: jusqu’à 16 PNG ordonnés, 2–64 options par question, dans le contexte combiné image/état/question. Le projecteur correspondant est téléchargé séparément depuis la même révision d’auteur. Les étiquettes de texte existantes de Winnow ne le chargent pas.
  • Un modèle qui ne lit aucune image répond à une requête avec images par un 422.

/v1/systemone et /v1/decisions restent identiques à l’API de TypeSafe, qui n’a pas de champ image.

Charger et décharger. Une requête sans state ni questions ne décide jamais. Sans keep_alive, ou avec une valeur positive ou négative, elle charge le modèle (chaque cible, pour un routeur) et renvoie done_reason: "load". Avec keep_alive: 0, elle le décharge ("unload"). ollaya run précharge ainsi, et ollaya stop décharge.

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}'

Une décision n’a aucun effet de bord sur les données stockées, donc tu peux la relancer sans risque.

Préréglages

Un préréglage est un ensemble de questions nommé. Six sont intégrés (triage, email, guard, moderation, router, agent), et tu peux enregistrer les tiens. Envoie "preset": "NAME" à /api/decide à la place 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 Corps Effet
GET /api/presets – Préréglages intégrés, puis personnalisés : name, builtin, description, ids de questions, modified_at
POST /api/presets/create name, questions, description (facultatif) Enregistre un préréglage personnalisé, en remplaçant celui de même nom
POST /api/presets/show name Un préréglage avec ses questions
DELETE /api/presets/delete name Supprime un préréglage personnalisé

Les noms font 1 à 64 caractères de lettres minuscules, de chiffres, de - et de _. Un nom intégré ne peut pas être réutilisé (422) ni supprimé (403), et un nom inconnu est un 404. Les préréglages personnalisés sont stockés à côté des modèles, donc chaque client du serveur voit les mêmes.

Routeurs

Un routeur comme laya (laya:latest) n’a pas de poids : pour chaque requête, il choisit une de ses cibles, qui répond ensuite. laya ne lit que le state :

État route Répondu par
Anglais english laya:en
Surtout une écriture non latine (arabe, cyrillique, CJK, …) multilingual laya:multilingual
Écriture latine, mais pas de l’anglais (turc, allemand, …) multilingual laya:multilingual
Aucune lettre english (le défaut) laya:en

Un texte court en majuscules sans lettres accentuées, comme des noms de commerçants sur un relevé bancaire (MIGROS KADIKOY ISTANBUL TR), des références ou des noms d’utilisateur, ne peut généralement pas être identifié et part vers laya:en. Si tu connais la langue, demande directement laya:multilingual ou laya:en ; le model de la réponse dit quel checkpoint a répondu.

Le routage coûte des microsecondes. Branche sur route, jamais sur reason, dont la formulation peut changer. laya:typed-decisions n’est jamais choisi par le routeur ; demande-le directement.

Lister les modèles locaux

GET /api/tags

Les modèles présents sur cette machine, du plus récent au plus ancien. Chaque entrée a name, model (le même), modified_at, size en octets, digest (sha256 du manifeste, hexadécimal nu) et details : parent_model, format (onnx, gguf ou router), family, families, parameter_size et quantization_level (les précisions qu’il porte, comme F16/F32, ou la quantification d’un modèle GGUF, comme 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"
      }
    }
  ]
}

Afficher les détails d’un modèle

POST /api/show
curl http://localhost:11435/api/show -d '{"model": "laya:en"}'
Champ Signification
license Texte de la licence
modelfile Un Modelfile qui recrée le modèle
parameters Paramètres fixés sur le modèle, un name value par ligne, comme precision fp32
questions Questions intégrées, ou null
router Pour un routeur : strategy, default et routes (route → modèle). null sinon.
details Comme dans /api/tags
model_info general.architecture, general.languages, general.source (le dépôt Hugging Face épinglé), plus des clés propres à la famille comme laya.context_length. general.languages liste les langues pour lesquelles le modèle a été entraîné et évalué (multilingual pour beaucoup) ; un modèle bâti sur une base multilingue peut quand même lire d’autres langues, donc mesure sur tes données.
capabilities Types de questions auxquels il répond (choice, score, noul), plus act s’il a une tête d’acte
modified_at Comme dans /api/tags

Un routeur s’affiche tel quel, sans être résolu vers une cible.

Lister les modèles en cours d’exécution

GET /api/ps

Les modèles chargés, triés par nom. Les routeurs n’apparaissent jamais ; leurs cibles chargées, oui. Chaque entrée a name, model, size (mémoire, RAM plus VRAM), digest, details (avec la précision réellement chargée : F16 ou F32, ou la quantification d’un modèle GGUF), expires_at (quand il se déchargera, ou null quand il est gardé chargé), size_vram, context_length et device (cpu, cuda:0, metal, …).

Télécharger un modèle

POST /api/pull
{"model": "laya:en"}

Télécharge le modèle dans le stockage local et vérifie chaque blob contre son sha256. Télécharger un routeur télécharge aussi chaque modèle vers lequel il route. Seules les couches dont cette machine a besoin sont téléchargées, les blobs partagés entre modèles ne sont téléchargés qu’une fois, et les téléchargements interrompus reprennent.

La réponse diffuse la progression, avec les chaînes de statut d’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 modèle n’apparaît dans /api/tags qu’après writing manifest. Pour un routeur il y a un seul success, tout à la fin. Un nom qui ne s’analyse pas, un modèle absent du registre et un registre injoignable sont des erreurs HTTP ordinaires (422, 404, 502) avant que le flux ne démarre, donc curl --fail fonctionne. Avec "stream": false, la réponse est {"status": "success"} une fois terminé. Un second téléchargement du même nom rejoint celui en cours. Relançable sans risque.

Supprimer un modèle

DELETE /api/delete
{"model": "triage"}

Supprime le nom, et les blobs qu’aucun autre modèle n’utilise. Un modèle chargé se décharge dès que ses requêtes se terminent ; supprimer un routeur conserve ses cibles. La réponse est 200 avec un corps vide, et 404 MODEL_NOT_FOUND quand le nom n’existe pas ; après un délai d’attente, considère cela comme un succès.

Copier un modèle

POST /api/copy
{"source": "laya:en", "destination": "my-guardrail"}

Copie un modèle sous un nouveau nom, en écrasant une destination existante. La réponse est 200 avec un corps vide.

Créer un modèle

POST /api/create

L’API derrière ollaya create -f Modelfile : la CLI lit le Modelfile et les fichiers qu’il nomme et envoie leur contenu en JSON.

Champ Type Requis Remarques
model string oui Nom à créer
from string oui Un modèle local, éventuellement un routeur. Il n’est jamais téléchargé.
questions object non Questions intégrées, validées comme une requête de décision
calibration object non temperature : jusqu’à 3 nombres (choice, score, noul). temperature_by_options : "<type>:<2|3-5|6-10|11+>" → nombre.
parameters object non precision : "fp16" ou "fp32", pour figer un graphe
license string or array non Texte(s) de licence
description string non Une ligne, affichée par /v1/models et ollaya show
stream boolean non Défaut 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"
}'

Le flux rapporte using existing layer sha256:… pour chaque couche héritée, creating new layer sha256:… pour chaque nouvelle, puis writing manifest et success. Les couches sont adressées par contenu, donc répéter une création donne le même modèle.

Version

GET /api/version
{"version": "0.1.0"}

Endpoints compatibles TypeSafe

Endpoint Description
POST /v1/systemone Requête : model, state (requis) et questions. Réponse : exactement model, answers et usage.
POST /v1/decisions Alias de /v1/systemone
GET /v1/models Les modèles locaux, sous la forme {"models": [{"name", "description", "release_date"}]}

/v1/* ignore les champs natifs comme keep_alive et extras, et n’ajoute jamais de champs natifs à ses réponses. Les erreurs utilisent le même corps que /api/*, que le SDK TypeSafe lit correctement. Voir Compatibilité TypeSafe.

Sécurité

Le serveur se lie à 127.0.0.1:11435 et, comme Ollama, fait confiance aux appelants locaux. Le lier à une autre adresse (OLLAYA_HOST=0.0.0.0) laisse quiconque peut atteindre le port lancer des décisions et télécharger, supprimer et créer des modèles, donc :

  • OLLAYA_API_KEY fait exiger Authorization: Bearer <key> à chaque requête sauf GET /, HEAD / et les prérequêtes CORS ; sinon la réponse est 401 UNAUTHORIZED. Le SDK TypeSafe envoie sa clé ainsi, et la CLI ollaya envoie $OLLAYA_API_KEY. Le serveur journalise un avertissement quand il écoute au-delà du loopback sans clé.
  • TLS n’est pas terminé par le serveur ; place un reverse proxy devant pour l’accès distant.
  • Navigateurs. Les requêtes avec un en-tête Origin ne sont autorisées que depuis localhost, 127.0.0.1, 0.0.0.0 et [::1] (n’importe quel port), les webviews d’applications et d’éditeurs, et les origines dans OLLAYA_ORIGINS (séparées par des virgules, jokers *). Un serveur en loopback rejette aussi les en-têtes Host inattendus, ce qui bloque le DNS rebinding.
  • Tes données. Les états et les questions ne sont jamais journalisés ni renvoyés dans les erreurs.
Variable Défaut Effet
OLLAYA_HOST 127.0.0.1:11435 Adresse de liaison ; la cible du client. Une adresse de loopback écoute aussi sur [::1], donc les programmes Windows atteignent sans délai un serveur dans WSL à localhost
OLLAYA_API_KEY non défini Exige Authorization: Bearer <key>
OLLAYA_ORIGINS non défini Origines de navigateur autorisées supplémentaires
OLLAYA_KEEP_ALIVE 5m keep_alive par défaut
OLLAYA_MAX_LOADED_MODELS 3 Limite de modèles chargés
OLLAYA_MAX_QUEUE 512 Requêtes en vol avant 503 QUEUE_FULL
OLLAYA_LOAD_TIMEOUT 5m Délai de chargement avant 500 MODEL_LOAD_FAILED
OLLAYA_DEVICE auto auto, cpu, cuda ou cuda:<n>
OLLAYA_MODELS ~/.ollaya/models Stockage des modèles
OLLAYA_REGISTRY ollaya.dev Hôte de registre par défaut dans les noms