Skip to content

Enterprise API

Multi-tenant scoring isolation, declarative policy rules, and audit logging. These modules are lazy-loaded — importing director_ai does not pull them in until accessed.

from director_ai.enterprise import TenantRouter, Policy, AuditLogger

PII Redaction

PIIRedactor masks sensitive values before prompts, responses, or audit payloads leave the tenant boundary. The default path is dependency-free regex PII detection with the Rust scanner used automatically when the backfire-kernel wheel is present. Presidio can still be added as an optional detector for named-entity enrichment in regulated deployments; the committed PII benchmark records Director and Presidio span-level precision/recall on the same labelled corpus so operators can compare detector behavior before enabling the optional stack.

from director_ai.enterprise import PIIRedactor

redactor = PIIRedactor()
report = redactor.redact_with_report(
    "Email jane.doe@example.com, call +1 415 555 0101, card 4111-1111-1111-1111."
)

assert report.redacted_text == "Email [EMAIL], call [PHONE], card [CARD]."
assert report.category_counts == {"card": 1, "email": 1, "phone": 1}

audit_payload = report.to_dict()
assert audit_payload["privacy"] == {
    "payload_classification": "tenant_safe",
    "raw_payload_included": False,
}

The structured report exposes detector name, category, offsets, replacement token, score, and category counts. It never serialises the raw matched value, so the report can be stored in tenant-safe audit metadata. Stable replacement tokens are [EMAIL], [PHONE], [CARD], [SSN], [IBAN], [IPV4], [PASSPORT], [PERSON], and [PHI]; unknown detector categories fall back to an uppercase bracketed token.

Content Moderation Wrapper

ContentModerator is the commercial wrapper for moderation enforcement. It combines PII redaction with toxicity detection and returns one decision: allow, redact, warn, or block. The default deployment path redacts PII with the dependency-free detector stack and blocks keyword toxicity; operators can inject stronger model-backed detectors or switch toxicity handling to warn-only mode.

from director_ai.enterprise import ContentModerator, ModerationAction

moderator = ContentModerator(toxicity_action=ModerationAction.BLOCK)
result = moderator.moderate("Email jane@example.com, then go kill yourself.")

assert result.blocked is True
assert result.safe_text == "Email [EMAIL], then go kill yourself."

audit_payload = result.to_dict()
assert audit_payload["privacy"] == {
    "payload_classification": "tenant_safe",
    "raw_input_included": False,
}

The wrapper's metadata contains detector names, categories, offsets, actions, scores, replacement tokens, and aggregate category counts. It does not serialise raw matched values. Use the lower-level RegexPIIDetector, PresidioPIIDetector, KeywordToxicityDetector, or DetoxifyDetector only when building a custom moderation policy.

Custom Rules DSL

CustomRuleset loads strict operator-owned JSON or YAML policy documents and compiles them into the existing runtime Policy engine. Unknown fields, duplicate rule identifiers, invalid regex patterns, invalid actions, invalid thresholds, and non-positive numeric limits are rejected before a policy can be registered.

version: director.rules.v1
name: tenant-alpha.safety
rules:
  - id: no-passwords
    kind: forbidden
    value: share passwords
    name: No password disclosure
    action: block
    source: security-baseline.md#L10
  - id: ticket-redaction
    kind: pattern
    value: "TICKET-\\d{6}"
    name: Ticket reference
    action: redact
  - id: length-cap
    kind: max_length
    value: 800
  - id: citations
    kind: required_citations
    value: 2
from director_ai.enterprise import CustomRuleset

ruleset = CustomRuleset.from_file("tenant-alpha.rules.yaml")
policy = ruleset.to_policy()

violations = policy.check("share passwords in TICKET-123456")
assert {violation.rule for violation in violations} == {
    "forbidden",
    "pattern:Ticket reference",
    "required_citations",
}

Supported rule kinds are forbidden, pattern, max_length, and required_citations; supported actions are block, warn, and redact. CustomRuleset.to_policy_bundle(version=...) returns the immutable compiler bundle when operators need deterministic registry hot-swap behaviour.

TenantRouter

Isolates scoring configuration per tenant. Each tenant gets its own CoherenceScorer instance with independent thresholds, knowledge bases, and caching.

from director_ai.enterprise import TenantRouter

router = TenantRouter()
# Tenants are provisioned implicitly: get_scorer returns a per-tenant
# CoherenceScorer, created on first use with the given threshold.
scorer_a = router.get_scorer("tenant_a", threshold=0.7, use_nli=True)
scorer_b = router.get_scorer("tenant_b", threshold=0.5, use_nli=False)

approved, score = scorer_a.review(query, response)

Policy

Declarative rule engine for content filtering. Runs before coherence scoring.

from director_ai.enterprise import Policy

policy = Policy(
    forbidden=[r"(buy|sell|short)\s+(stock|shares)"],
    patterns=[{"name": "ssn", "regex": r"\b(SSN|social security)\b", "action": "block"}],
    max_length=4000,
)

violations = policy.check(response_text)
for violation in violations:
    print(f"Policy violation: {violation.rule}{violation.detail}")

AuditLogger

SQLite-backed audit logging for compliance. Records every review decision with full context.

from director_ai.enterprise import AuditLogger

logger = AuditLogger(path="/var/log/director-ai/audit.db")
logger.log_review(query, response, approved=True, score=0.91, tenant_id="tenant_a")

# Verify the tamper-evident hash chain
ok, error = logger.verify_chain()
assert ok, error

License Matrix

The enterprise module is part of the Advanced & Labs tier, licensed under BUSL-1.1 (source-available).

Use Case License Required
Evaluation / prototyping BUSL-1.1 (free)
Non-production internal use BUSL-1.1 (free)
Production deployment Commercial license
Hosted / SaaS product Commercial license

The Apache-2.0 core, by contrast, is free in production. See Licensing for pricing and terms.

Full API

director_ai.core.tenant.TenantRouter

TenantRouter()

Routes requests to tenant-isolated GroundTruthStores.

Thread-safe: stores are created lazily on first access. Supports per-tenant fine-tuned model selection.

tenant_ids property

tenant_ids: list[str]

Return tenant ids that currently have in-memory stores.

get_store

get_store(tenant_id: str) -> GroundTruthStore

Get or create an isolated store for this tenant.

add_fact

add_fact(tenant_id: str, key: str, value: str) -> None

Add a fact to a specific tenant's store.

remove_tenant

remove_tenant(tenant_id: str) -> bool

Remove a tenant and all its data. Returns True if existed.

get_vector_store

get_vector_store(tenant_id: str, backend_type: str = 'memory', **kwargs: Any) -> VectorGroundTruthStore

Get or create a tenant-isolated VectorGroundTruthStore.

Supported backend_type values: "memory", "chroma", "pinecone", "qdrant". Extra kwargs are forwarded to the backend constructor.

set_model

set_model(tenant_id: str, model_id: str, model_path: str, balanced_accuracy: float = 0.0, regression_pp: float = 0.0, recommendation: str = '', dataset_hash: str = '') -> ModelVersion

Register a fine-tuned model for a tenant.

activate_model

activate_model(tenant_id: str, model_id: str) -> bool

Activate a specific model version for a tenant. Deactivates others.

rollback_model

rollback_model(tenant_id: str) -> bool

Deactivate all models for a tenant (revert to baseline).

get_active_model

get_active_model(tenant_id: str) -> ModelVersion | None

Return the active model for a tenant, or None for baseline.

list_models

list_models(tenant_id: str) -> list[ModelVersion]

List all model versions for a tenant.

delete_model

delete_model(tenant_id: str, model_id: str) -> bool

Remove a model version. Cannot delete active models.

get_scorer

get_scorer(tenant_id: str, threshold: float = 0.6, use_nli: bool | None = None) -> CoherenceScorer

Build a CoherenceScorer scoped to this tenant's KB and model.

save_manifest

save_manifest(path: str | Path) -> None

Save all tenant model metadata to a JSON manifest.

load_manifest

load_manifest(path: str | Path) -> int

Load tenant model metadata from a JSON manifest. Returns count loaded.

fact_count

fact_count(tenant_id: str) -> int

Return the number of facts in a tenant's store.

director_ai.core.safety.audit.AuditLogger

AuditLogger(path: str | Path | None = None, logger_name: str = 'DirectorAI.Audit', hmac_secret: str | None = None)

Structured audit logger with file and logging sinks.

Parameters:

Name Type Description Default
path str | Path | None — JSONL file path. None = logging-only.
None
logger_name str — Python logger name for audit events.
'DirectorAI.Audit'

add_sink

add_sink(sink: Any) -> None

Add an external consumer for audit records (e.g. PostgresAuditSink).

log_review

log_review(query: str, response: str, approved: bool, score: float, h_logical: float = 0.0, h_factual: float = 0.0, policy_violations: list[str] | None = None, tenant_id: str = '', halt_reason: str = '', latency_ms: float = 0.0, kb_snapshot: dict[str, Any] | None = None) -> AuditEntry

Record a review decision.

verify_chain

verify_chain(path: str | Path | None = None) -> tuple[bool, int | None]

Re-derive the on-disk hash chain and report the first tampered entry.

Returns (ok, first_bad_index). ok is False when any record's payload was altered (content hash mismatch), the chain linkage was broken (a record deleted, reordered, or its prev_hash edited), or a tag fails (HMAC mismatch — needs the same secret that wrote the log). first_bad_index is the 0-based line index, None on success.

director_ai.enterprise.redactor.PIIRedactor

PIIRedactor(enabled: bool = True, *, detectors: Sequence[ModerationDetector] | None = None, prefer_rust: bool = True)

Enterprise redaction pipeline for sensitive string values.

redact_with_report

redact_with_report(text: str) -> PIIRedactionReport

Redact PII and return a tenant-safe structured report.

redact

redact(text: str) -> str

Redact known PII patterns from the text string.

__call__

__call__(text: str) -> str

Redact the given text and return the sanitised result.

director_ai.enterprise.redactor.PIIRedactionReport dataclass

PIIRedactionReport(redacted_text: str, findings: tuple[PIIRedactionFinding, ...])

PII redaction result and tenant-safe metadata.

redacted property

redacted: bool

Whether at least one PII span was replaced.

category_counts property

category_counts: dict[str, int]

Return stable redaction counts grouped by category.

to_dict

to_dict() -> dict[str, object]

Serialise a tenant-safe report suitable for audit logs.

director_ai.enterprise.moderation.ContentModerator

ContentModerator(*, enable_pii: bool = True, toxicity_action: ModerationAction = ModerationAction.BLOCK, toxicity_detectors: Sequence[ModerationDetector] | None = None, prefer_rust: bool = True)

Production wrapper for PII redaction and toxicity moderation.

moderate

moderate(text: str) -> ContentModerationResult

Moderate text and return the safe text plus tenant-safe metadata.

director_ai.enterprise.moderation.ContentModerationResult dataclass

ContentModerationResult(action: ModerationAction, safe_text: str, findings: tuple[ContentModerationFinding, ...])

Result of a content moderation pass.

blocked property

blocked: bool

Whether the moderation result blocks downstream release.

category_counts property

category_counts: dict[str, int]

Return stable finding counts grouped by category.

to_dict

to_dict() -> dict[str, object]

Serialise a tenant-safe moderation report.

director_ai.enterprise.rules_dsl.CustomRuleset

Bases: BaseModel

Versioned JSON/YAML ruleset with strict schema validation.

from_dict classmethod

from_dict(data: dict[str, Any]) -> CustomRuleset

Load a ruleset from a parsed JSON/YAML mapping.

from_json classmethod

from_json(text: str) -> CustomRuleset

Load a ruleset from JSON text.

from_yaml classmethod

from_yaml(text: str) -> CustomRuleset

Load a ruleset from YAML text.

from_file classmethod

from_file(path: str | Path) -> CustomRuleset

Load a ruleset from a JSON, YAML, or YML file.

to_policy_bundle

to_policy_bundle(*, version: int = 1) -> PolicyBundle

Convert into an immutable policy compiler bundle.

to_policy

to_policy() -> Policy

Convert into the runtime safety policy.

to_dict

to_dict() -> dict[str, Any]

Serialise the ruleset into deterministic JSON-compatible data.

to_json

to_json() -> str

Serialise the ruleset into deterministic JSON text.

director_ai.enterprise.rules_dsl.CustomRule

Bases: BaseModel

One validated custom policy rule.

compiled_name property

compiled_name: str

Return the runtime rule name shown in policy violations.

compiled_action property

compiled_action: RuleAction

Return the runtime action, defaulting to the compiler contract.

to_compiled_rule

to_compiled_rule() -> CompiledRule

Convert into the existing policy compiler rule contract.