Files
tibi-types/schemas/config/embedding.schema.json
T
apairon 5a45c4dd3f feat(types): Embedding-Abschnitt der Server-Config (Provider, Failover-Gruppen, goldener Pfad) + Status-Payloads
index.d.ts: EmbeddingProviderConfig/EmbeddingGroupConfig (onSingleQuery, onBulkWrite,
health), EmbeddingConfig für config.server().embedding (Roh-JSON von config.Server.
Embedding) sowie die Status-Payloads von GET …/admin/embedding/status (Projekt- und
Server-Scope, Zustände live|degraded|quarantined|offline, Breaker closed|open|half-open).
VectorConfig.provider dokumentiert jetzt, dass dort auch ein Gruppenname stehen darf.

schemas/config/embedding.schema.json: validierbares Schema des Server-Abschnitts
(Enums für Policies/Distributionen, Go-Duration-Muster, Pflichtfelder, keine
erfundenen Properties); Beispiel examples/server/embedding.yml, per
scripts/validate-schemas.mjs mitgeprüft (npm test: 5 YAML gegen 17 Schemas).

Quelle der Wahrheit: internal/config/server.go + internal/config/embedding_group.go
(tibi-server). Typecheck: tsc --noEmit --strict über index.d.ts grün.
2026-10-17 14:00:53 +00:00

256 lines
9.2 KiB
JSON

{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "embedding.schema.json",
"title": "Tibi server config — embedding section (server-level, not project config)",
"description": "Der Abschnitt `embedding` aus der Server-config.yml (server.embedding): Provider + Failover-Gruppen + Gold-Datei-Pfad. Quelle der Wahrheit: internal/config/server.go und internal/config/embedding_group.go im tibi-server.",
"type": "object",
"additionalProperties": false,
"properties": {
"providers": {
"type": "array",
"items": {
"$ref": "#/definitions/provider"
}
},
"groups": {
"type": "array",
"items": {
"$ref": "#/definitions/group"
}
},
"goldenPath": {
"type": "string",
"description": "Verzeichnis der Gold-Dateien für die Mitglieds-Prüfung (Vorgabe: testdata/embedding-golden relativ zum Arbeitsverzeichnis). Erzeugen mit cmd/embed-probe-golden. Ohne verankerte Gold-Datei prüft die Gruppe nur gegen ihre Referenz."
}
},
"definitions": {
"duration": {
"type": "string",
"description": "Go-Duration, z. B. 120s, 800ms, 25s",
"pattern": "^[0-9]+(\\.[0-9]+)?(ns|us|µs|ms|s|m|h)+$"
},
"provider": {
"type": "object",
"additionalProperties": false,
"required": [
"name"
],
"properties": {
"name": {
"type": "string",
"description": "Provider-Name; Sammlungen referenzieren ihn (oder eine Gruppe) über vector.provider."
},
"type": {
"type": "string",
"enum": [
"native",
"flagembedding"
],
"description": "native = ONNX im Prozess (braucht -tags cgo_embedding), flagembedding = externer HTTP-Endpunkt. Ohne Angabe: native."
},
"model": {
"type": "string"
},
"modelPath": {
"type": "string",
"description": "ONNX-Modellverzeichnis (type: native)."
},
"dimensions": {
"type": "integer",
"minimum": 1
},
"baseURL": {
"type": "string",
"description": "Embedding-Endpunkt (type: flagembedding)."
},
"apiKey": {
"type": "string"
},
"documentPrefix": {
"type": "string"
},
"queryPrefix": {
"type": "string"
},
"timeoutPerAttempt": {
"$ref": "#/definitions/duration",
"description": "flagembedding: HTTP-Timeout (Vorgabe 120s); native: Schranke je Embed-Aufruf (nur am Aufruf-/Stufen-Eintritt wirksam, ONNX-Runs sind nicht unterbrechbar). Ungültige oder nicht-positive Werte werden ignoriert (Warnung im Log)."
},
"slowThreshold": {
"$ref": "#/definitions/duration",
"description": "Nur gruppenwirksam: langsamere Aufrufe zählen für lowest-latency als langsam."
},
"revision": {
"type": "string",
"description": "Gewichts-/Build-Tag (Datei-Hash, Quantisierung); fließt in die Modell-Identität ein (Gruppen-Prüfung, Query-Cache)."
},
"sparse": {
"type": "boolean",
"description": "false = Endpunkt/Modell liefert keine Sparse-Vektoren: native lädt die Sparse-Session nicht, flagembedding schweigt die einmalige Dense-only-Warnung; in einer Gruppe lehnt die Prüfung abweichende Sparse-Formen ab."
}
}
},
"group": {
"type": "object",
"additionalProperties": false,
"required": [
"name",
"members"
],
"properties": {
"name": {
"type": "string",
"description": "Gruppenname; darf kein Provider-Name sein und darf nur einmal vorkommen."
},
"description": {
"type": "string"
},
"members": {
"type": "array",
"minItems": 1,
"uniqueItems": true,
"items": {
"type": "string"
},
"description": "Provider-Namen der Gruppe. Alle Mitglieder müssen dieselbe Modell-Identität liefern (Dimensionen, Sparse-Unterstützung, revision)."
},
"onSingleQuery": {
"type": "object",
"additionalProperties": false,
"properties": {
"policy": {
"type": "string",
"enum": [
"prefer-in-order",
"fastest-wins",
"round-robin",
"lowest-latency",
"weighted"
]
},
"preferredOrder": {
"description": "Bevorzugte Reihenfolge; als Komma-String oder YAML-Liste. Mitglieder, die fehlen, hängen in Config-Reihenfolge hinten an.",
"oneOf": [
{
"type": "string"
},
{
"type": "array",
"items": {
"type": "string"
}
}
]
},
"timeoutPerAttempt": {
"$ref": "#/definitions/duration",
"description": "Schranke je Versuch. Der bevorzugte Member läuft genau darin; Ausweich-Member bekommen max(Provider-Timeout, dieser Wert)."
},
"timeoutTotal": {
"$ref": "#/definitions/duration",
"description": "Gesamt-Deadline je Aufruf; muss >= timeoutPerAttempt sein."
},
"autoFailback": {
"type": "boolean",
"description": "true (Vorgabe) = jeder Aufruf beginnt wieder beim bevorzugten Mitglied; false = bleibt beim letzten Gewinner."
},
"raceDelay": {
"$ref": "#/definitions/duration",
"description": "Nur policy fastest-wins: Staffelung zwischen den Teilnehmern."
},
"raceMaxFanout": {
"type": "integer",
"minimum": 0,
"description": "Nur policy fastest-wins: maximale parallele Teilnehmer (0 = alle)."
},
"weights": {
"type": "array",
"items": {
"type": "integer",
"minimum": 0
},
"description": "Nur policy weighted: relative Gewichte je Mitglied, positional zur members-Liste."
},
"latencyWindow": {
"type": "integer",
"minimum": 1,
"description": "Fenster für die EWMA-Latenz (lowest-latency)."
},
"retryAttempts": {
"type": "integer",
"minimum": 0
},
"retryBackoff": {
"$ref": "#/definitions/duration"
},
"retryBackoffMax": {
"$ref": "#/definitions/duration"
},
"hedgeAfterSlow": {
"$ref": "#/definitions/duration",
"description": "prefer-in-order: nach dieser Dauer starten die übrigen Mitglieder parallel (Hedge)."
}
}
},
"onBulkWrite": {
"type": "object",
"additionalProperties": false,
"properties": {
"distribution": {
"type": "string",
"enum": [
"round-robin",
"lowest-latency",
"weighted"
],
"description": "Verteilung der Batch-Ranges über die Mitglieder; ohne Angabe kein Sharding (serieller Schreibpfad). Jeder Range bleibt ganz auf einem Mitglied."
},
"maxConcurrentTotal": {
"type": "integer",
"minimum": 0
},
"maxConcurrentPerEndpoint": {
"type": "integer",
"minimum": 0,
"description": "Pro Mitglied; lokale (native) Mitglieder sind auf 1 begrenzt."
},
"timeoutPerAttempt": {
"$ref": "#/definitions/duration",
"description": "Bulk-Schranke je Versuch; pro Mitglied gilt max(Provider-Timeout, dieser Wert)."
},
"timeoutTotal": {
"$ref": "#/definitions/duration"
}
}
},
"health": {
"type": "object",
"additionalProperties": false,
"properties": {
"checkInterval": {
"$ref": "#/definitions/duration",
"description": "Abstand der Health-Probes. > 0 aktiviert zusätzlich den Late-Join: quarantänisierte Mitglieder (und offline Gruppen) werden gegen die aktuelle Referenz neu geprüft und kommen zurück, sobald sie passen. 0 = nur Neustart hilft."
},
"checkTimeout": {
"$ref": "#/definitions/duration",
"description": "Schranke je Probe-Embed; die Rundenschranke beim Start skaliert mit der Zahl der Probe-Texte."
},
"unhealthyAfterFailures": {
"type": "integer",
"minimum": 0
},
"healthyAfterSuccesses": {
"type": "integer",
"minimum": 0
},
"cooldownAfterUnhealthy": {
"$ref": "#/definitions/duration",
"description": "Pause, bevor ein offenes Mitglied wieder halb geöffnet wird (danach genügt Verkehr, kein Probe-Lauf)."
}
}
}
}
}
}
}