Files
Onyscribe-Admin/vendor/platform/core/hooks.py
RubenRWU 7d8c226da2 Onyscribe Admin: Initialer Stand
Admin-Plattform für die Tenants von Onyscribe: Editor mit Live-Vorschau (echter Core in Sandbox), Versionen, KI-Agent (Cortecs),
OIDC-Abgleich über die Login-Developer-API, Deploy-Engine (Mittwald, gesperrt ohne DEPLOY_LIVE, Freigabe pro Tenant),
Core-Vertrag (Schema/Manifest), Core-Releases mit Kompatibilitätsprüfung, Canary-Rollout und Rollback, Zustandsabgleich.
Runbook: docs/RUNBOOK_PARALLELTEST.md

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 15:30:26 +02:00

65 lines
2.3 KiB
Python

"""Per-tenant code hooks.
Most customers differ only in *data* (colours, logo, prompt, PDF template) and
need no code here. For the few that need genuine behaviour changes, drop an
`overrides.py` into their tenant folder defining a `Hooks(TenantHooks)` subclass
that overrides only the methods it needs. Core stays untouched, so core updates
keep flowing.
Example tenants/acme/overrides.py:
from core.hooks import TenantHooks
class Hooks(TenantHooks):
def build_prompt(self, base, ctx):
return base + "\\nBevorzuge Fachterminologie aus der Orthopädie."
def extra_routes(self, app):
@app.get("/health/acme")
def _h():
return {"ok": True}
"""
from __future__ import annotations
import importlib.util
from pathlib import Path
from core.contract import HOOK_API
class TenantHooks:
"""Default (no-op) behaviour. Override selectively per tenant."""
def build_prompt(self, base_prompt: str, ctx: dict) -> str:
"""Adjust the system prompt sent to the LLM. ctx carries the form fields."""
return base_prompt
def transform_transcript(self, transcript: str, ctx: dict) -> str:
"""Post-process the transcript before summarisation/delivery."""
return transcript
def pdf_context(self, context: dict) -> dict:
"""Last chance to enrich/alter the data passed to the PDF template."""
return context
def extra_routes(self, app) -> None:
"""Register tenant-specific FastAPI routes."""
return None
def load_hooks(tenant_dir: Path) -> TenantHooks:
override = tenant_dir / "overrides.py"
if not override.exists():
return TenantHooks()
spec = importlib.util.spec_from_file_location(f"tenant_overrides_{tenant_dir.name}", override)
module = importlib.util.module_from_spec(spec)
assert spec and spec.loader
spec.loader.exec_module(module)
declared = getattr(module, "HOOK_API", HOOK_API) # fehlt die Deklaration, gilt die aktuelle Version
if declared != HOOK_API:
raise RuntimeError(f"{override}: HOOK_API={declared} wird von diesem Core nicht unterstützt (Core: {HOOK_API})")
hooks_cls = getattr(module, "Hooks", None)
if hooks_cls is None:
return TenantHooks()
return hooks_cls()