Dokumentation

API-Referenz

ollaya serve stellt zwei APIs auf http://localhost:11435 bereit:

  • die native API unter /api/*, modelliert nach Ollamas API, für Entscheidungen und Modellverwaltung;
  • die TypeSafe-kompatible API unter /v1/*, wire-identisch mit TypeSafe, sodass vorhandene TypeSafe-SDKs unverändert funktionieren. Siehe TypeSafe-Kompatibilität.
Methode Pfad Zweck
GET, HEAD / Lebendigkeit: Ollaya is running
GET /api/version Serverversion
POST /api/decide Beantwortet typisierte Fragen zu einem Zustand; lädt und entlädt außerdem ein Modell
GET /api/tags Modelle auf diesem Rechner
POST /api/show Details zu einem Modell
GET /api/ps In den Speicher geladene Modelle
POST /api/pull Lädt ein Modell herunter (streamt den Fortschritt)
DELETE /api/delete Entfernt ein Modell
POST /api/copy Kopiert ein Modell unter einen neuen Namen
POST /api/create Erstellt ein Modell aus einem anderen (streamt den Fortschritt)
POST /v1/systemone TypeSafe System One
POST /v1/decisions Alias von /v1/systemone
GET /v1/models TypeSafe-Modellliste

/api/push und /api/blobs/:digest sind reserviert und antworten 501 NOT_IMPLEMENTED. Ollamas Text-Endpunkte (/api/generate, /api/chat, /api/embed) antworten 404: Entscheidungsmodelle erzeugen nie Text.

Konventionen

  • JSON. Anfrage- und Antwortkörper sind JSON-Objekte. Der Körper wird unabhängig von seinem Content-Type als JSON geparst, curl -d funktioniert also unverändert. Anfragen sind höchstens 8 MiB groß.
  • Feldnamen sind snake_case. Unbekannte Anfragefelder werden ignoriert; null bedeutet abwesend.
  • Modellnamen sind [host/][namespace/]model[:tag], ohne Beachtung der Groß-/Kleinschreibung. Ein fehlender Tag bedeutet latest. Antworten verwenden immer die kanonische Form, etwa laya:latest.
  • Zahlen. Wahrscheinlichkeiten, Konfidenzen, score und noul werden auf 4 Nachkommastellen gerundet. Dauern sind ganze Zahlen in Nanosekunden; Zeitstempel sind RFC 3339 in UTC.
  • Streaming. /api/pull und /api/create streamen zeilenweise getrenntes JSON, ein Objekt pro Zeile, und enden mit genau einem {"status":"success"} oder einer Fehlerzeile. Sende "stream": false für eine einzelne Antwort.
  • Request-IDs. Jede Antwort trägt X-Request-Id, und /v1/*-Antworten zusätzlich x-typesafe-request-id. Eine gültige, vom Client gesendete X-Request-Id wird zurückgegeben.
  • Nebenläufigkeit. Ein geladenes Modell führt jeweils eine Anfrage aus, und jede Anfrage beantwortet alle ihre Fragen in einem Durchlauf. Anfragen an dasselbe Modell werden in eine Warteschlange gestellt, mehr gleichzeitig zu senden wird also nicht schneller fertig; die Umlaufzeit jeder einzelnen enthält dann die Wartezeit. Stelle jede Frage zu einem Zustand in einer Anfrage. Verschiedene geladene Modelle laufen parallel.
  • Keine impliziten Pulls. Kein Endpunkt lädt ein Modell als Nebenwirkung herunter. ollaya run lädt zuerst herunter; Anwendungen rufen /api/pull auf.

Fehler

Jeder Fehler hat an jedem Endpunkt diesen Körper:

{
  "error": "model \"laya:xl\" not found, try pulling it first",
  "code": "MODEL_NOT_FOUND"
}
Feld Bedeutung
error Für Menschen lesbare Meldung. Parse sie nicht; die eine eingefrorene Meldung ist model "<name>" not found, try pulling it first, wie in Ollama.
code Maschinenlesbarer Code. Verzweige danach.
detail Nur für INVALID_REQUEST, TOO_MANY_OPTIONS, INPUT_TOO_LONG und STATE_TRUNCATED: jedes Validierungsproblem in der ValidationError-Form von TypeSafe (FastAPI): loc, msg, type und manchmal ctx.
Code HTTP Wann Wiederholen
INVALID_JSON 400 Körper fehlt, ist kein JSON oder kein Objekt nein
INVALID_REQUEST 422 Körper besteht die Validierung nicht; detail listet jedes Problem auf nein
TOO_MANY_OPTIONS 422 Die Optionen einer Frage passen nicht in das Optionsbudget des Modells nein
INPUT_TOO_LONG 422 state ist länger als 65.536 Token nein
STATE_TRUNCATED 422 /v1/systemone oder /v1/decisions würde einen Teil von state verwerfen, um in den Kontext des Modells zu passen nein
UNAUTHORIZED 401 OLLAYA_API_KEY ist gesetzt und der Anfrage fehlt der Schlüssel nein
FORBIDDEN 403 Browser-Header Origin oder Host nicht erlaubt nein
MODEL_NOT_FOUND 404 Modell (oder das Ziel eines Routers) nicht auf diesem Rechner; bei einem Pull nicht in der Registry nein
NOT_FOUND 404 Kein solcher Endpunkt nein
METHOD_NOT_ALLOWED 405 Endpunkt existiert, Methode nicht nein
OPERATION_IN_PROGRESS 409 Ein Pull oder Create schreibt denselben Modellnamen danach
REQUEST_TOO_LARGE 413 Körper über 8 MiB nein
QUEUE_FULL 503 OLLAYA_MAX_QUEUE Anfragen warten bereits; gesendet mit Retry-After: 1 ja
MODEL_LOAD_FAILED 500 Das Modell konnte nicht geladen werden (beschädigte Dateien, Speicher, OLLAYA_LOAD_TIMEOUT) selten
INFERENCE_FAILED 500 Der Runner ist während einer Entscheidung fehlgeschlagen ja
STORAGE_ERROR 500 Datenträger voll, Berechtigungen oder E/A nein
INTERNAL 500 Ein Bug; das Serverprotokoll hat Details unter der Request-ID ja
UNSUPPORTED_MODEL 501 Dieser Build kann das Format des Modells nicht ausführen nein
NOT_IMPLEMENTED 501 Reservierter Endpunkt nein
REGISTRY_ERROR 502 Registry nicht erreichbar oder ungültig ja
DIGEST_MISMATCH 502 Ein Download passte nicht zu seinem sha256 und wurde verworfen ja

Die Menge der Codes ist offen: Behandle einen unbekannten anhand seines HTTP-Status. Ein Validierungsfehler listet jedes Problem auf einmal auf:

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

Sobald ein Stream begonnen hat, kommt ein Fehler als letzte Zeile in derselben Form, etwa {"error": "…", "code": "DIGEST_MISMATCH"}. Prüfe jede Zeile auf error, bevor du sie als Fortschritt liest.

Fragen

/api/decide, /v1/systemone und /api/create teilen sich ein Fragenschema, das von TypeSafe. Eine Anfrage hat 1–256 Fragen, mit einer beliebigen ID als Schlüssel; die Antworten kommen in derselben Reihenfolge zurück.

type instructions criteria Antwort
choice optional erforderlich: Objektlabel → Beschreibung oder ein Array von Labels; 2–255 Optionen choice, confidence, probabilities
score optional erforderlich: Array von Stufenbeschreibungen, Stufe 0 zuerst; 2–10 Stufen score, confidence, legend, probabilities
noul optional optional: {"true": "…", "false": "…"} noul
  • instructions kann ein String, ein Objekt, ein Array oder null sein. Fehlt es oder ist es null, liest das Modell stattdessen die Frage-ID, sodass eine beschreibende ID wie is_spam für sich allein funktioniert.
  • state ist ein String, ein Objekt oder ein Array, bis zu 65.536 Token. Überschreitet er den verfügbaren Kontext des Modells, kürzt /api/decide ihn und meldet state_truncated: true. /v1/systemone und /v1/decisions geben 422 STATE_TRUNCATED zurück, mit dem antwortenden Modell in detail[0].ctx.model.
  • Modellgrenzen. Jede Option braucht Platz im Kontext des Modells: etwa 125 Optionen für laya:en (512 Token) und 250 für laya:multilingual (1.024). Mehr ergibt 422 TOO_MANY_OPTIONS. Bei einem Router gelten die Grenzen des Ziels.

Antworten sind TypeSafe-Formen, in dieser Feldreihenfolge:

type Felder
choice choice: das wahrscheinlichste Label. confidence. probabilities: Label → Wahrscheinlichkeit, in der Reihenfolge der criteria.
score score: die erwartete Stufe Σ i·pᵢ, die zwischen Stufen liegen kann. confidence. legend: "0"… → die Beschreibung der Stufe. probabilities: "0"… → Wahrscheinlichkeit.
noul noul: die Wahrscheinlichkeit, dass die Aussage zutrifft. Keine confidence, wie in TypeSafe.

confidence ist die von TypeSafe normalisierte Spitzenwahrscheinlichkeit, (K · pmax − 1) / (K − 1) für K Optionen: 0, wenn jede Option gleich wahrscheinlich ist, 1, wenn eine Option die ganze Wahrscheinlichkeit auf sich vereint. Die Formel ist für jedes Modell dieselbe, was eine gegebene Konfidenz bedeutet, aber nicht: Modelle sind unterschiedlich kalibriert, stimme einen Schwellenwert also pro Modell auf deinen eigenen Daten ab. Wahrscheinlichkeiten werden mit den Temperaturen jedes Modells kalibriert. Auf einer CUDA-GPU läuft der fp16-Graph, dessen Antworten bei knappen Ausgängen von fp32 abweichen können.

keep_alive

Wie lange ein Modell nach dem Ende einer Anfrage geladen bleibt, mit Ollamas Semantik:

Wert Bedeutung
"5m", "1h30m", "300ms", 300, "300" Bleibt so lange nach der Anfrage geladen
0, "0", "0s" Entlädt, sobald die Anfrage beendet ist
-1, "-5m", jeder negative Wert Bleibt geladen, bis der Server stoppt oder ein explizites Entladen erfolgt
fehlend oder null OLLAYA_KEEP_ALIVE, Standard 5m

Der Timer startet, wenn eine Anfrage endet, und der Wert der letzten Anfrage gewinnt. Bei einem Router gilt er für das Ziel, das geantwortet hat. /v1/* ignoriert keep_alive.

Decide

POST /api/decide

Beantwortet typisierte Fragen zu einem Zustand in einem Vorwärtsdurchlauf. Der Körper ist der Körper von /v1/systemone plus native Optionen; die Antwort ist TypeSafes Antwort plus native Felder, sodass auch ein TypeSafe-Client sie parsen kann.

Feld Typ Erforderlich Hinweise
model string ja Modellname
state string, object or array ja, um zu entscheiden Ohne ihn lädt oder entlädt die Anfrage das Modell (unten)
questions object ja, außer das Modell hat eingebaute Fragen Ersetzt die eingebauten Fragen des Modells vollständig
preset string nein Der Name eines Presets, eingebaut oder eigen, anstelle von questions
images array of strings nein Für ein Vision-Modell: PNG-Bilder, base64 oder base64-data:-URLs. Decider nimmt eines; winnow:e4b-vision nimmt bis zu 16. Siehe Bilder
keep_alive string or number nein Siehe keep_alive
extras array of strings nein ["laya"] fügt jeder Antwort layas eigene Konfidenz und Act-Wahrscheinlichkeit hinzu
stream boolean nein Reserviert; true wird abgelehnt
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
}
Feld Bedeutung
model Das Modell, das geantwortet hat: bei einem Router sein Ziel (laya:en für eine laya-Anfrage)
answers Frage-ID → Antwort, in der Reihenfolge der Fragen
usage Gelesene input_tokens; output_tokens ist immer 0
routing Bei einem Router: router, das gewählte model, ein stabiler route-Schlüssel und ein informativer reason. Sonst null.
state_truncated true, wenn ein Teil des Zustands verworfen wurde, um in den Kontext des Modells zu passen
done_reason "decide", "load" oder "unload"
created_at Wann die Antwort erzeugt wurde
total_duration Nanosekunden vom Empfang der Anfrage bis zur Antwort, Warteschlange inbegriffen
load_duration Nanosekunden, die darauf gewartet wurde, dass das Modell lädt; 0, wenn es warm war
eval_duration Nanosekunden im Runner: Tokenisierung, Vorwärtsdurchlauf, Kalibrierung

Mit "extras": ["laya"] hat jede Antwort außerdem ein laya-Objekt: confidence (layas entropiebasierte Konfidenz) und act_probability (aus dem Act-Head des Modells oder null).

Bilder

Ein Vision-Modell (decider:2b-vision oder winnow:e4b-vision) beantwortet Fragen zu einem Bild ebenso wie zum Zustand. Sende das Bild in images, base64-kodiert, so wie Ollamas images funktioniert:

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: Ein Bild pro Anfrage, nur PNG. Die Vorverarbeitung des Modells wird Wert für Wert reproduziert, die Pixel müssen also zu dem passen, was die Autoren des Modells dekodieren. Rusts JPEG-Decoder weichen bei manchen Pixeln um bis zu 4 Stufen von libjpeg-turbo ab, JPEG wird deshalb noch nicht akzeptiert: Konvertiere es zuerst nach PNG.
  • Decider: Das Bild wird auf Vielfache von 32 Pixeln skaliert, wie das Modell es erwartet, und kann danach höchstens 4.096 Patches von 16x16 Pixeln haben, etwa ein Megapixel (1024x1024). Ein größeres Bild erhält eine 422, die das sagt; skaliere es zuerst herunter.
  • Decider: Fragen haben höchstens 10 Optionen. Dasselbe Modell beantwortet auch reine Textanfragen.
  • Winnow E4B vision: bis zu 16 geordnete PNGs, 2–64 Optionen pro Frage, im kombinierten Bild-/Zustands-/Fragekontext. Der passende Projektor wird separat aus derselben Autoren-Revision heruntergeladen. Bestehende Winnow-Text-Tags laden ihn nicht.
  • Ein Modell, das keine Bilder liest, beantwortet eine Anfrage mit images mit einer 422.

/v1/systemone und /v1/decisions bleiben identisch mit der API von TypeSafe, die kein Bildfeld hat.

Laden und Entladen. Eine Anfrage ohne state und questions entscheidet nie. Ohne keep_alive oder mit einem positiven oder negativen lädt sie das Modell (bei einem Router jedes Ziel) und gibt done_reason: "load" zurück. Mit keep_alive: 0 entlädt sie es ("unload"). ollaya run lädt auf diese Weise vor, und ollaya stop entlädt.

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

Eine Entscheidung hat keine Nebenwirkung auf gespeicherte Daten, ein erneuter Versuch ist also sicher.

Presets

Ein Preset ist ein benannter Fragensatz. Sechs sind eingebaut (triage, email, guard, moderation, router, agent), und du kannst eigene speichern. Sende "preset": "NAME" an /api/decide anstelle von 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"}'
Endpunkt Körper Wirkung
GET /api/presets – Eingebaute Presets, dann eigene: name, builtin, description, Frage-IDs, modified_at
POST /api/presets/create name, questions, description (optional) Speichert ein eigenes Preset und ersetzt eines mit demselben Namen
POST /api/presets/show name Ein Preset mit seinen Fragen
DELETE /api/presets/delete name Löscht ein eigenes Preset

Namen bestehen aus 1 bis 64 Zeichen aus Kleinbuchstaben, Ziffern, - und _. Ein eingebauter Name kann nicht wiederverwendet (422) oder gelöscht (403) werden, und ein unbekannter Name ist ein 404. Eigene Presets werden neben den Modellen gespeichert, sodass jeder Client des Servers dieselben sieht.

Router

Ein Router wie laya (laya:latest) hat keine Gewichte: Für jede Anfrage wählt er eines seiner Ziele, das dann antwortet. laya liest nur den state:

Zustand route Beantwortet von
Englisch english laya:en
Überwiegend nicht-lateinische Schrift (Arabisch, Kyrillisch, CJK, …) multilingual laya:multilingual
Lateinische Schrift, aber nicht Englisch (Türkisch, Deutsch, …) multilingual laya:multilingual
Überhaupt keine Buchstaben english (der Standard) laya:en

Kurzer Text in Großbuchstaben ohne akzentuierte Buchstaben, etwa Händlernamen auf einem Kreditkartenauszug (MIGROS KADIKOY ISTANBUL TR), SKUs oder Benutzernamen, lässt sich meist nicht identifizieren und geht an laya:en. Wenn du die Sprache kennst, fordere laya:multilingual oder laya:en direkt an; das model der Antwort sagt, welcher Checkpoint geantwortet hat.

Routing kostet Mikrosekunden. Verzweige nach route, niemals nach reason, dessen Formulierung sich ändern kann. laya:typed-decisions wird vom Router nie gewählt; fordere es direkt an.

Lokale Modelle auflisten

GET /api/tags

Die Modelle auf diesem Rechner, neueste zuerst. Jeder Eintrag hat name, model (denselben), modified_at, size in Bytes, digest (sha256 des Manifests, reines Hex) und details: parent_model, format (onnx, gguf oder router), family, families, parameter_size und quantization_level (die mitgeführten Genauigkeiten wie F16/F32 oder die Quantisierung eines GGUF-Modells wie 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"
      }
    }
  ]
}

Modelldetails anzeigen

POST /api/show
curl http://localhost:11435/api/show -d '{"model": "laya:en"}'
Feld Bedeutung
license Lizenztext
modelfile Ein Modelfile, das das Modell neu erstellt
parameters Am Modell gesetzte Parameter, ein name value pro Zeile, etwa precision fp32
questions Eingebaute Fragen oder null
router Bei einem Router: strategy, default und routes (Route → Modell). Sonst null.
details Wie in /api/tags
model_info general.architecture, general.languages, general.source (das festgeschriebene Hugging-Face-Repository) plus familienspezifische Schlüssel wie laya.context_length. general.languages listet die Sprachen, für die das Modell trainiert und evaluiert wurde (multilingual für viele); ein Modell auf einer mehrsprachigen Basis kann trotzdem andere Sprachen lesen, miss das also an deinen eigenen Daten.
capabilities Fragetypen, die es beantwortet (choice, score, noul), plus act, wenn es einen Act-Head hat
modified_at Wie in /api/tags

Ein Router wird als er selbst angezeigt, nicht zu einem Ziel aufgelöst.

Laufende Modelle auflisten

GET /api/ps

Die geladenen Modelle, nach Namen sortiert. Router erscheinen nie; ihre geladenen Ziele schon. Jeder Eintrag hat name, model, size (Speicher, RAM plus VRAM), digest, details (mit der tatsächlich geladenen Genauigkeit: F16 oder F32 oder die Quantisierung eines GGUF-Modells), expires_at (wann es entladen wird, oder null, wenn geladen gehalten), size_vram, context_length und device (cpu, cuda:0, metal, …).

Ein Modell herunterladen

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

Lädt das Modell in den lokalen Speicher herunter und prüft jeden Blob gegen seinen sha256. Ein Router lädt beim Pull auch jedes Modell herunter, an das er weiterleitet. Nur die Ebenen, die dieser Rechner braucht, werden heruntergeladen, zwischen Modellen geteilte Blobs werden einmal heruntergeladen, und unterbrochene Downloads werden fortgesetzt.

Die Antwort streamt den Fortschritt, mit Ollamas Status-Strings:

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

Ein Modell erscheint erst nach writing manifest in /api/tags. Bei einem Router gibt es ein success, ganz am Ende. Ein Name, der sich nicht parsen lässt, ein Modell, das nicht in der Registry ist, und eine nicht erreichbare Registry sind gewöhnliche HTTP-Fehler (422, 404, 502), bevor der Stream beginnt, curl --fail funktioniert also. Mit "stream": false ist die Antwort nach Abschluss {"status": "success"}. Ein zweiter Pull desselben Namens schließt sich dem laufenden an. Ein erneuter Versuch ist sicher.

Ein Modell löschen

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

Entfernt den Namen und die Blobs, die kein anderes Modell verwendet. Ein geladenes Modell wird entladen, sobald seine Anfragen beendet sind; das Löschen eines Routers behält seine Ziele. Die Antwort ist 200 mit leerem Körper und 404 MODEL_NOT_FOUND, wenn der Name nicht existiert; behandle das nach einem Timeout als Erfolg.

Ein Modell kopieren

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

Kopiert ein Modell unter einen neuen Namen und überschreibt ein vorhandenes Ziel. Die Antwort ist 200 mit leerem Körper.

Ein Modell erstellen

POST /api/create

Die API hinter ollaya create -f Modelfile: Die CLI liest das Modelfile und die darin genannten Dateien und sendet ihren Inhalt als JSON.

Feld Typ Erforderlich Hinweise
model string ja Name zum Erstellen
from string ja Ein lokales Modell, möglicherweise ein Router. Es wird nie heruntergeladen.
questions object nein Eingebaute Fragen, validiert wie eine Entscheidungsanfrage
calibration object nein temperature: bis zu 3 Zahlen (choice, score, noul). temperature_by_options: "<type>:<2|3-5|6-10|11+>" → Zahl.
parameters object nein precision: "fp16" oder "fp32", um einen Graphen festzulegen
license string or array nein Lizenztext(e)
description string nein Eine Zeile, angezeigt von /v1/models und ollaya show
stream boolean nein Standard 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"
}'

Der Stream meldet using existing layer sha256:… für jede geerbte Ebene, creating new layer sha256:… für jede neue, dann writing manifest und success. Ebenen sind inhaltsadressiert, ein wiederholtes Create ergibt also dasselbe Modell.

Version

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

TypeSafe-kompatible Endpunkte

Endpunkt Beschreibung
POST /v1/systemone Anfrage: model, state (erforderlich) und questions. Antwort: genau model, answers und usage.
POST /v1/decisions Alias von /v1/systemone
GET /v1/models Die lokalen Modelle als {"models": [{"name", "description", "release_date"}]}

/v1/* ignoriert native Felder wie keep_alive und extras und fügt seinen Antworten nie native Felder hinzu. Fehler verwenden denselben Körper wie /api/*, den das TypeSafe-SDK korrekt liest. Siehe TypeSafe-Kompatibilität.

Sicherheit

Der Server bindet an 127.0.0.1:11435 und vertraut wie Ollama lokalen Aufrufern. Bindest du ihn an eine andere Adresse (OLLAYA_HOST=0.0.0.0), kann jeder, der den Port erreicht, Entscheidungen ausführen sowie Modelle herunterladen, löschen und erstellen, also:

  • OLLAYA_API_KEY lässt jede Anfrage außer GET /, HEAD / und CORS-Preflight Authorization: Bearer <key> erfordern; andernfalls lautet die Antwort 401 UNAUTHORIZED. Das TypeSafe-SDK sendet seinen Schlüssel so, und die ollaya-CLI sendet $OLLAYA_API_KEY. Der Server protokolliert eine Warnung, wenn er über Loopback hinaus ohne Schlüssel lauscht.
  • TLS wird nicht vom Server terminiert; stelle für den Fernzugriff einen Reverse-Proxy davor.
  • Browser. Anfragen mit einem Origin-Header sind nur von localhost, 127.0.0.1, 0.0.0.0 und [::1] (beliebiger Port), App- und Editor-Webviews und den Ursprüngen in OLLAYA_ORIGINS (durch Kommas getrennt, *-Platzhalter) erlaubt. Ein Loopback-Server lehnt außerdem unerwartete Host-Header ab, was DNS-Rebinding blockiert.
  • Deine Daten. Zustände und Fragen werden nie protokolliert und nie in Fehlern zurückgegeben.
Variable Standard Wirkung
OLLAYA_HOST 127.0.0.1:11435 Bind-Adresse; das Ziel des Clients. Eine Loopback-Adresse lauscht auch auf [::1], sodass Windows-Programme einen Server in WSL unter localhost ohne Verzögerung erreichen
OLLAYA_API_KEY nicht gesetzt Erfordert Authorization: Bearer <key>
OLLAYA_ORIGINS nicht gesetzt Zusätzliche erlaubte Browser-Ursprünge
OLLAYA_KEEP_ALIVE 5m Standard-keep_alive
OLLAYA_MAX_LOADED_MODELS 3 Limit geladener Modelle
OLLAYA_MAX_QUEUE 512 Anfragen in Bearbeitung, bevor 503 QUEUE_FULL kommt
OLLAYA_LOAD_TIMEOUT 5m Ladefrist, bevor 500 MODEL_LOAD_FAILED kommt
OLLAYA_DEVICE auto auto, cpu, cuda oder cuda:<n>
OLLAYA_MODELS ~/.ollaya/models Modellablage
OLLAYA_REGISTRY ollaya.dev Standard-Registry-Host in Namen