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, donccurl -dfonctionne 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 ;nullsignifie absent. - Noms de modèles. Ils sont
[host/][namespace/]model[:tag], insensibles à la casse. Un tag absent signifielatest. Les réponses utilisent toujours la forme canonique, commelaya:latest. - Nombres. Les probabilités, les confiances, le
scoreet lenoulsont arrondis à 4 décimales. Les durées sont des entiers en nanosecondes ; les horodatages sont en RFC 3339 en UTC. - Streaming.
/api/pullet/api/creatediffusent 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": falsepour une réponse unique. - IDs de requête. Chaque réponse porte
X-Request-Id, et les réponses/v1/*aussix-typesafe-request-id. UnX-Request-Idvalide 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 runté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 |
instructionspeut être une chaîne, un objet, un tableau ounull. Quand il est absent ounull, le modèle lit à la place l’id de la question, donc un id descriptif commeis_spamsuffit à lui seul.stateest une chaîne, un objet ou un tableau, jusqu’à 65 536 jetons. S’il dépasse le contexte disponible du modèle,/api/decidele tronque et rapportestate_truncated: true./v1/systemoneet/v1/decisionsrenvoient422 STATE_TRUNCATEDavec le modèle qui a répondu dansdetail[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 pourlaya:multilingual(1 024). Au-delà, c’est422 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
imagespar 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_KEYfait exigerAuthorization: Bearer <key>à chaque requête saufGET /,HEAD /et les prérequêtes CORS ; sinon la réponse est401 UNAUTHORIZED. Le SDK TypeSafe envoie sa clé ainsi, et la CLIollayaenvoie$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
Originne sont autorisées que depuislocalhost,127.0.0.1,0.0.0.0et[::1](n’importe quel port), les webviews d’applications et d’éditeurs, et les origines dansOLLAYA_ORIGINS(séparées par des virgules, jokers*). Un serveur en loopback rejette aussi les en-têtesHostinattendus, 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 |