Compare commits
7
Commits
4c55f82446
..
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f26f8c7802 | ||
|
|
439c8773e6 | ||
|
|
21472bdc72 | ||
|
|
9e12a8e9c3 | ||
|
|
3bf8055539 | ||
|
|
1233bd393d | ||
|
|
5a45c4dd3f |
No files matched your search
@@ -0,0 +1,43 @@
|
||||
name: ngram-stopwords
|
||||
uploadPath: ../media/ngram-stopwords
|
||||
|
||||
permissions: !include global/test-permissions.yml
|
||||
|
||||
fields:
|
||||
- name: title
|
||||
type: string
|
||||
meta:
|
||||
label:
|
||||
de: Titel
|
||||
en: Title
|
||||
widget: "text"
|
||||
|
||||
search:
|
||||
- name: fuzzy
|
||||
mode: ngram
|
||||
fields: [title]
|
||||
autoRegenerate: true
|
||||
ngram:
|
||||
sizes: [2, 3]
|
||||
normalize:
|
||||
use: [german-umlauts]
|
||||
stopwords:
|
||||
presets: [de, en]
|
||||
words: [zum, zur]
|
||||
queryFilter:
|
||||
minMatchRatio: 0.4
|
||||
inMemory:
|
||||
enabled: true
|
||||
maxDocs: 150000
|
||||
maxMemoryMB: 512
|
||||
- name: combined
|
||||
mode: combined
|
||||
rrf:
|
||||
k: 60
|
||||
topK: 100
|
||||
weights:
|
||||
fuzzy: 1.0
|
||||
combinedCache:
|
||||
enabled: true
|
||||
ttl: 45s
|
||||
maxEntries: 1000
|
||||
@@ -4,6 +4,18 @@ namespace: myapi
|
||||
meta:
|
||||
# wird in der Admin-UI zum Projekt aufgegeben
|
||||
imageUrl: https://source.unsplash.com/random/?internet
|
||||
tools:
|
||||
- name: demo-overview
|
||||
label:
|
||||
de: Demo-Übersicht
|
||||
en: Demo overview
|
||||
description:
|
||||
de: Beispiel-Tool für die Projekt-Übersicht
|
||||
en: Example project overview tool
|
||||
icon: view-dashboard-outline
|
||||
group: tools
|
||||
module: _/assets/tools/demo-overview/index.js
|
||||
capabilities: [db, ui, log]
|
||||
|
||||
# Liste aller möglichen Kollektionen (Listen, Seiten...) zum Projekt
|
||||
collections:
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
# Beispiel für den embedding-Abschnitt der Server-config.yml
|
||||
# (tibi-server, server.embedding) — validiert gegen schemas/config/embedding.schema.json.
|
||||
providers:
|
||||
- name: bge-m3-external
|
||||
type: flagembedding
|
||||
model: BAAI/bge-m3
|
||||
dimensions: 1024
|
||||
baseURL: https://embed.intern/embed
|
||||
timeoutPerAttempt: 8s
|
||||
slowThreshold: 1500ms
|
||||
- name: bge-m3-local
|
||||
type: native
|
||||
model: BAAI/bge-m3
|
||||
dimensions: 1024
|
||||
modelPath: /models/bge-m3
|
||||
timeoutPerAttempt: 60s
|
||||
groups:
|
||||
- name: bge-m3-main
|
||||
description: Bevorzugt extern, sonst lokal, kehrt automatisch zurück.
|
||||
members:
|
||||
- bge-m3-external
|
||||
- bge-m3-local
|
||||
onSingleQuery:
|
||||
policy: prefer-in-order
|
||||
preferredOrder:
|
||||
- bge-m3-external
|
||||
- bge-m3-local
|
||||
timeoutPerAttempt: 8s
|
||||
timeoutTotal: 1m30s # Mehrfach-Einheiten sind erlaubt (Go time.ParseDuration)
|
||||
|
||||
autoFailback: true
|
||||
retryAttempts: 1
|
||||
retryBackoff: 200ms
|
||||
retryBackoffMax: 2s
|
||||
latencyWindow: "100"
|
||||
|
||||
onBulkWrite:
|
||||
distribution: lowest-latency
|
||||
maxConcurrentTotal: 6
|
||||
maxConcurrentPerEndpoint: 2
|
||||
timeoutPerAttempt: 15s
|
||||
timeoutTotal: 120s
|
||||
health:
|
||||
checkInterval: 30s
|
||||
checkTimeout: 3s
|
||||
unhealthyAfterFailures: 3
|
||||
healthyAfterSuccesses: 2
|
||||
cooldownAfterUnhealthy: 60s
|
||||
goldenPath: testdata/embedding-golden
|
||||
Vendored
+265
@@ -81,9 +81,33 @@ declare global {
|
||||
eval?: string
|
||||
}
|
||||
|
||||
export interface NgramStopwordsConfig {
|
||||
presets?: string[]
|
||||
words?: string[]
|
||||
}
|
||||
|
||||
export interface NgramQueryFilterConfig {
|
||||
minMatchRatio?: number
|
||||
}
|
||||
|
||||
export interface CombinedCacheConfig {
|
||||
enabled?: boolean
|
||||
ttl?: string
|
||||
maxEntries?: number
|
||||
}
|
||||
|
||||
export interface NgramInMemoryConfig {
|
||||
enabled?: boolean
|
||||
maxDocs?: number
|
||||
maxMemoryMB?: number
|
||||
}
|
||||
|
||||
export interface NgramConfig {
|
||||
sizes?: number[]
|
||||
normalize?: NormalizeConfig
|
||||
stopwords?: NgramStopwordsConfig
|
||||
queryFilter?: NgramQueryFilterConfig
|
||||
inMemory?: NgramInMemoryConfig
|
||||
}
|
||||
|
||||
export interface RrfConfig {
|
||||
@@ -109,6 +133,12 @@ declare global {
|
||||
}
|
||||
|
||||
export interface VectorConfig {
|
||||
/**
|
||||
* Name of the embedding provider (server config: `embedding.providers`) or
|
||||
* of an embedding failover group (`embedding.groups`). Groups route across
|
||||
* their members (policy, breaker, bulk sharding) and look like one provider
|
||||
* to the collection.
|
||||
*/
|
||||
provider: string
|
||||
documentPrefix?: string
|
||||
queryPrefix?: string
|
||||
@@ -169,6 +199,8 @@ declare global {
|
||||
filter?: { [key: string]: any }
|
||||
/** Ngram search configuration */
|
||||
ngram?: NgramConfig
|
||||
/** Result cache for combined searches */
|
||||
combinedCache?: CombinedCacheConfig
|
||||
/** Regex search configuration */
|
||||
regex?: RegexConfig
|
||||
/** Custom scoring for eval/filter search */
|
||||
@@ -561,6 +593,121 @@ declare global {
|
||||
[key: string]: any
|
||||
}
|
||||
|
||||
// ── Custom Tools (Admin) ─────────────────────────────────────────────────
|
||||
|
||||
/** Project config entry (`meta.tools[]`). */
|
||||
export interface AdminToolConfig {
|
||||
name: string
|
||||
label?: string | { [lang: string]: string }
|
||||
description?: string | { [lang: string]: string }
|
||||
icon?: string
|
||||
group?: string
|
||||
module: string | { eval: string }
|
||||
permissions?: string[]
|
||||
capabilities?: Array<"db" | "files" | "xlsx" | "ui" | "log" | "progress" | "state">
|
||||
settings?: Record<string, any>
|
||||
hidden?: boolean
|
||||
}
|
||||
|
||||
/** File handle handed to tools (data URL, no live Blob). */
|
||||
export interface AdminToolFile {
|
||||
src: string
|
||||
name: string
|
||||
type?: string
|
||||
size?: number
|
||||
}
|
||||
|
||||
/** Fail-fast batch result; no rollback. */
|
||||
export interface AdminToolBatchResult {
|
||||
ok: boolean
|
||||
failedIndex?: number
|
||||
error?: unknown
|
||||
}
|
||||
|
||||
export interface AdminToolDb {
|
||||
find(
|
||||
collection: string,
|
||||
opts?: Record<string, any>
|
||||
): Promise<CollectionDocument[]>
|
||||
count(collection: string, opts?: Record<string, any>): Promise<number>
|
||||
loadAll(
|
||||
collection: string,
|
||||
opts?: Record<string, any>,
|
||||
onProgress?: (done: number, total: number) => void
|
||||
): Promise<CollectionDocument[]>
|
||||
create(collection: string, data: Record<string, any>): Promise<CollectionDocument>
|
||||
update(collection: string, id: string, data: Record<string, any>): Promise<Partial<CollectionDocument>>
|
||||
delete(collection: string, id: string): Promise<void>
|
||||
updateMany(collection: string, items: Array<{ id: string; data: Record<string, any> }>): Promise<AdminToolBatchResult>
|
||||
deleteMany(collection: string, ids: string[]): Promise<AdminToolBatchResult>
|
||||
}
|
||||
|
||||
export interface AdminToolUi {
|
||||
supports(type: string): boolean
|
||||
slot(el: HTMLElement, element: any): void
|
||||
styles: CSSStyleSheet[]
|
||||
registerWidget(type: string, factory: (...args: any[]) => any, opts?: { replace?: boolean }): () => void
|
||||
render(el: HTMLElement, widget: Record<string, any>): void | (() => void)
|
||||
field(opts: Record<string, any>): any
|
||||
form(opts: Record<string, any>): any
|
||||
[key: string]: any
|
||||
}
|
||||
|
||||
export interface AdminToolI18n {
|
||||
lang: string
|
||||
languages: string[]
|
||||
t(key: string, vars?: Record<string, unknown>): string
|
||||
text(value: string | Record<string, string> | undefined | null, vars?: Record<string, unknown>): string
|
||||
has(key: string): boolean
|
||||
add(lang: string, messages: Record<string, unknown>): () => void
|
||||
add(messages: Record<string, unknown>, lang?: string): () => void
|
||||
extend(lang: string, messages: Record<string, unknown>): () => void
|
||||
extend(messages: Record<string, unknown>, lang?: string): () => void
|
||||
onChange(cb: (lang: string) => void): () => void
|
||||
dispose?(): void
|
||||
}
|
||||
|
||||
/** Browser context handed to a tool module. `context === ctx`. */
|
||||
export interface AdminToolContext {
|
||||
context: AdminToolContext
|
||||
apiVersion: 1
|
||||
uiVersion: 1
|
||||
host: "tool" | "macro" | "server"
|
||||
capabilities: string[]
|
||||
project: ProjectInfo
|
||||
tool: AdminToolConfig
|
||||
auth: { id: string; username: string; role: number; permissions: string[] } | null
|
||||
db: AdminToolDb
|
||||
files: { get(input: File | Blob | string, name?: string): Promise<AdminToolFile> }
|
||||
xlsx: any
|
||||
state: Map<string, unknown>
|
||||
lang: string
|
||||
languages: string[]
|
||||
i18n: AdminToolI18n
|
||||
theme: { mode: "light" | "dark"; tokens: Record<string, string> }
|
||||
log(message: string, details?: unknown): void
|
||||
progress(done: number, total: number, label?: string): void
|
||||
signal: AbortSignal
|
||||
hostData: Record<string, any>
|
||||
asset(specifier: string): string
|
||||
ui: AdminToolUi
|
||||
}
|
||||
|
||||
export interface AdminToolModule {
|
||||
mount(
|
||||
el: HTMLElement,
|
||||
ctx: AdminToolContext
|
||||
): void | (() => void) | Promise<void | (() => void)>
|
||||
messages?: Record<string, Record<string, any>>
|
||||
}
|
||||
|
||||
export interface AdminToolException {
|
||||
status?: number
|
||||
msg: string
|
||||
json?: any
|
||||
}
|
||||
|
||||
|
||||
/** Represents a single audit log entry as received in audit.return hooks */
|
||||
export interface AuditLogEntry {
|
||||
id?: string
|
||||
@@ -735,6 +882,122 @@ declare global {
|
||||
job?: JobConfig
|
||||
}
|
||||
|
||||
/**
|
||||
* Embedding provider as exposed by `config.server()` — mirror of
|
||||
* `ConfigEmbeddingProvider` (secrets and modelPath are stripped from the JSON).
|
||||
*/
|
||||
export interface EmbeddingProviderConfig {
|
||||
name: string
|
||||
/** "native" (ONNX in-process) or "flagembedding" (external HTTP endpoint) */
|
||||
type: string
|
||||
model?: string
|
||||
dimensions?: number
|
||||
baseURL?: string
|
||||
documentPrefix?: string
|
||||
queryPrefix?: string
|
||||
/** flagembedding: HTTP bound; native: per-call bound (entry-only) */
|
||||
timeoutPerAttempt?: string
|
||||
/** Group-only metric knob (feeds lowest-latency routing) */
|
||||
slowThreshold?: string
|
||||
/** Weights/build tag; part of the model identity used by groups */
|
||||
revision?: string
|
||||
/** false = endpoint/model has no sparse vectors (native skips the sparse session) */
|
||||
sparse?: boolean
|
||||
}
|
||||
|
||||
/** Single-query routing of an embedding group (`onSingleQuery`). */
|
||||
export interface EmbeddingOnSingleQueryConfig {
|
||||
policy?:
|
||||
| "prefer-in-order"
|
||||
| "fastest-wins"
|
||||
| "round-robin"
|
||||
| "lowest-latency"
|
||||
| "weighted"
|
||||
/** Comma-separated names (YAML list is joined with commas before marshalling) */
|
||||
preferredOrder?: string
|
||||
timeoutPerAttempt?: string
|
||||
timeoutTotal?: string
|
||||
autoFailback?: boolean
|
||||
raceDelay?: string
|
||||
raceMaxFanout?: number
|
||||
weights?: number[]
|
||||
/** Digits as string (Go field is a string, validated with Atoi; must be > 0) */
|
||||
latencyWindow?: string
|
||||
retryAttempts?: number
|
||||
retryBackoff?: string
|
||||
retryBackoffMax?: string
|
||||
hedgeAfterSlow?: string
|
||||
}
|
||||
|
||||
/** Bulk-write sharding of an embedding group (`onBulkWrite`). */
|
||||
export interface EmbeddingOnBulkWriteConfig {
|
||||
distribution?: "round-robin" | "lowest-latency" | "weighted"
|
||||
maxConcurrentTotal?: number
|
||||
maxConcurrentPerEndpoint?: number
|
||||
timeoutPerAttempt?: string
|
||||
timeoutTotal?: string
|
||||
}
|
||||
|
||||
/** Health/breaker timing of an embedding group (`health`). */
|
||||
export interface EmbeddingHealthConfig {
|
||||
/** > 0 also enables late join/recovery of quarantined members */
|
||||
checkInterval?: string
|
||||
checkTimeout?: string
|
||||
unhealthyAfterFailures?: number
|
||||
healthyAfterSuccesses?: number
|
||||
cooldownAfterUnhealthy?: string
|
||||
}
|
||||
|
||||
/** Embedding failover group as exposed by `config.server()`. */
|
||||
export interface EmbeddingGroupConfig {
|
||||
name: string
|
||||
description?: string
|
||||
members: string[]
|
||||
onSingleQuery?: EmbeddingOnSingleQueryConfig
|
||||
onBulkWrite?: EmbeddingOnBulkWriteConfig
|
||||
health?: EmbeddingHealthConfig
|
||||
}
|
||||
|
||||
/** Embedding section as exposed by `config.server()`. */
|
||||
export interface EmbeddingConfig {
|
||||
providers?: EmbeddingProviderConfig[]
|
||||
groups?: EmbeddingGroupConfig[]
|
||||
/** Directory of golden verification files (default testdata/embedding-golden) */
|
||||
goldenPath?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Member state from `GET …/admin/embedding/status` (server scope keeps
|
||||
* `lastError`, project scope redacts it).
|
||||
*/
|
||||
export interface EmbeddingMemberHealth {
|
||||
state: "live" | "degraded" | "quarantined" | "offline"
|
||||
breaker: "closed" | "open" | "half-open"
|
||||
lastError?: string
|
||||
latencyMs?: number
|
||||
successes?: number
|
||||
failures?: number
|
||||
slowCount?: number
|
||||
}
|
||||
|
||||
/** Group state from `GET …/admin/embedding/status`. */
|
||||
export interface EmbeddingGroupHealth {
|
||||
/** null while no member is live */
|
||||
referenceMember: string | null
|
||||
members: { [member: string]: EmbeddingMemberHealth }
|
||||
}
|
||||
|
||||
/** Project-scope payload: `{ namespace, health: { groups } }`. */
|
||||
export interface EmbeddingHealthProjectResponse {
|
||||
namespace: string
|
||||
health: { groups: { [group: string]: EmbeddingGroupHealth } }
|
||||
}
|
||||
|
||||
/** Server-scope payload: `{ groups }`. */
|
||||
export interface EmbeddingHealthServerResponse {
|
||||
groups: { [group: string]: EmbeddingGroupHealth }
|
||||
}
|
||||
|
||||
interface ConfigPackage {
|
||||
/**
|
||||
* get current namespace string
|
||||
@@ -773,6 +1036,8 @@ declare global {
|
||||
maxTokensPerRequest?: number
|
||||
}[]
|
||||
}
|
||||
/** Raw JSON of config.Server.Embedding (apiKey/modelPath stripped, JSON tags decide) */
|
||||
embedding?: EmbeddingConfig
|
||||
audit?: {
|
||||
enabled: boolean
|
||||
defaultTTL: string
|
||||
|
||||
@@ -321,7 +321,8 @@
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "integer",
|
||||
"minimum": 1
|
||||
"minimum": 2,
|
||||
"maximum": 10
|
||||
}
|
||||
},
|
||||
"normalize": {
|
||||
@@ -338,6 +339,68 @@
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"stopwords": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"presets": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"words": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"queryFilter": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"minMatchRatio": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
"inMemory": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"enabled": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"maxDocs": {
|
||||
"type": "integer",
|
||||
"minimum": 0
|
||||
},
|
||||
"maxMemoryMB": {
|
||||
"type": "integer",
|
||||
"minimum": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"combinedCache": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"enabled": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"ttl": {
|
||||
"type": "string"
|
||||
},
|
||||
"maxEntries": {
|
||||
"type": "integer",
|
||||
"minimum": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -0,0 +1,255 @@
|
||||
{
|
||||
"$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 (time.ParseDuration), z. B. 120s, 800ms, 25s, 1m30s, 1.5h",
|
||||
"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": "string",
|
||||
"pattern": "^[0-9]+$",
|
||||
"description": "Fenster für die EWMA-Latenz (lowest-latency) als Ziffern-String (> 0); Go-Feld ist ein String, der per Atoi geprüft wird."
|
||||
},
|
||||
"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)."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -65,6 +65,21 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
"ui": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"css": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"tools": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "tool.schema.json"
|
||||
}
|
||||
},
|
||||
"i18n": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
@@ -89,6 +104,20 @@
|
||||
"code"
|
||||
]
|
||||
}
|
||||
},
|
||||
"messages": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "Custom Tool",
|
||||
"description": "Project custom tool entry (meta.tools[]).",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"name",
|
||||
"module"
|
||||
],
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"pattern": "^[a-z0-9][a-z0-9-_]*$"
|
||||
},
|
||||
"label": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"$ref": "defs.schema.json#/definitions/i18nText"
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"$ref": "defs.schema.json#/definitions/i18nText"
|
||||
}
|
||||
]
|
||||
},
|
||||
"icon": {
|
||||
"type": "string"
|
||||
},
|
||||
"group": {
|
||||
"type": "string"
|
||||
},
|
||||
"module": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"$ref": "defs.schema.json#/definitions/evalString"
|
||||
}
|
||||
]
|
||||
},
|
||||
"permissions": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"capabilities": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"enum": [
|
||||
"db",
|
||||
"files",
|
||||
"xlsx",
|
||||
"ui",
|
||||
"log",
|
||||
"progress",
|
||||
"state"
|
||||
]
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"type": "object"
|
||||
},
|
||||
"hidden": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -64,6 +64,9 @@ const validations = [
|
||||
{ schema: "job.schema.json", pattern: "demo-api/jobs/*.y*ml" },
|
||||
{ schema: "action.schema.json", pattern: "demo-api/actions/*.y*ml" },
|
||||
{ schema: "asset.schema.json", pattern: "demo-api/assets/*.y*ml" },
|
||||
// Server-level Abschnitt (config.yml des tibi-servers), Beispiel getrennt
|
||||
// vom Projekt-Demo unter examples/server/:
|
||||
{ schema: "embedding.schema.json", pattern: "examples/server/*.y*ml" },
|
||||
]
|
||||
|
||||
let hasErrors = false
|
||||
|
||||
Reference in new issue
Block a user