feat(gateway): Jev (System One) as primary text moderator with LLM fallback (#80)
* feat(gateway): Jev (System One) as primary text moderator with LLM fallback Add TypeSafe Jev via @typesafe-ai/sdk v0.6.0 as the PRIMARY analyzer for text-only moderation sub-batches; the existing LLM stays as the fallback for anything Jev cannot decide confidently (per-message gate rejection or API failure) and for media batches. - jevAnalyzer.ts: TypeSafeClient wrapper, declarative state builder (System One models MUST get factual state, not chat-XML — chat framing made Jev confidently wrong on clean messages at 0.98 confidence), message-id-keyed question builder (5 typed questions per message), cross-consistency acceptance gate (noul↔status↔severity↔action↔category), answer→AnalysisResult mapper, fail-open outcome. - textBatchProcessor.ts: Jev-first per sub-batch, rejected ids + API failures fall back to callModerationLLM; no cross-batch pollution. - config: AI_LLM_JEV_ENABLED/API_KEY/BASE_URL/MODEL/TIMEOUT_MS/MIN_CONFIDENCE. - .env.example: documented all 6 Jev env vars. - tests: unit (question/state builders, gate, mapper) + live smoke (gated behind AI_LLM_JEV_SMOKE=1) verified 4/4 accepted vs real 9router. * fix: auto-fix code quality [skip ci]
This commit is contained in:
@@ -193,6 +193,23 @@ export const configSchema = z
|
||||
// (AI_LLM_BASE_URL) but a different model alias. The dedicated NVIDIA
|
||||
// multimodal endpoint was removed.
|
||||
AI_LLM_VISION_MODEL: z.string().default("multimodal"),
|
||||
// ── Jev (TypeSafe System One) — primary text analyzer ────────────────
|
||||
// Jev evaluates typed questions against a state and returns calibrated
|
||||
// structured answers (no text generation). Runs on 9router's
|
||||
// /v1/systemone (free model oc/jev-1.13-free). The existing LLM remains
|
||||
// the fallback for anything Jev cannot decide confidently and for media.
|
||||
AI_LLM_JEV_ENABLED: z
|
||||
.string()
|
||||
.optional()
|
||||
.transform((v) => v === "true")
|
||||
.default(true),
|
||||
AI_LLM_JEV_API_KEY: z.string().optional().default(""),
|
||||
AI_LLM_JEV_BASE_URL: z.string().url().default("http://127.0.0.1:4014"),
|
||||
AI_LLM_JEV_MODEL: z.string().default("oc/jev-1.13-free"),
|
||||
// Per-message acceptance threshold on the status choice confidence.
|
||||
// Below this the message falls back to the LLM (fail-open).
|
||||
AI_LLM_JEV_MIN_CONFIDENCE: z.coerce.number().min(0).max(1).default(0.9),
|
||||
AI_LLM_JEV_TIMEOUT_MS: z.coerce.number().int().positive().default(45_000),
|
||||
AI_LLM_DISABLE_THINKING: z
|
||||
.string()
|
||||
.default("true")
|
||||
|
||||
Reference in New Issue
Block a user