Skip to main content

enterprise-agentic-ai-framework

An enterprise governance framework for building single- and multi-agent AI systems in Python: authorization, guardrails, observability, secrets management, LLM gateway access, and a full production evaluation suite, all as one consistent stack instead of one-off code per project.

pip install enterprise-agentic-ai-framework

The import name is agentic_ai (the PyPI distribution name is longer for naming reasons, the package you actually import is not):

from agentic_ai.gateway import LiteLLMGateway

Status

This is an early release. The LLM gateway, the full evaluation suite, Memory & State, Context Engineering, Secrets Management, Guardrails & Content Safety, Authentication, Identity, Governance (in full - authorization, audit, security, data, compliance, responsible AI, finops), Resilience & Reliability, Observability, and Monitoring & Alerting are implemented today - everything else below is scaffolded (the module exists, it's empty) and not yet usable. This table will be kept current as modules land, not written once and left stale.

Module Status
gateway - LLM gateway (LiteLLM proxy client) ✅ Implemented
evaluation - Agent/LLM/Tools/Multi-Agent/RAG/Security/Platform/Memory/Drift evaluation (48 metrics, see below) ✅ Implemented
memory - session/agent/short-term/working/long-term/semantic/episodic/procedural/document/shared memory & state (see below) ✅ Implemented
context - context engineering: assembly, write, select, compress, isolate (see below) ✅ Implemented
secrets - secrets management: HashiCorp Vault (KV v2, dynamic secrets, Transit encryption) (see below) ✅ Implemented
guardrails - input/output guardrails, injection/jailbreak/content-safety/PII detection, tool gating, rate limiting, human-in-the-loop (see below) ✅ Implemented
authentication - credential mechanics: Keycloak (OIDC/OAuth2 grants, MFA, mTLS, token validation/refresh/revocation, auto-refresh) (see below) ✅ Implemented
identity - claims/data layer: TokenClaims, UserInfo, Tenant Identity Isolation (see below) ✅ Implemented
governance.authorization - PDP/PEP via Open Policy Agent: RBAC/ABAC/fine-grained authorization (see below) ✅ Implemented
governance.audit - durable, hash-chained audit trail + adapters for every other module's audit wrapper (see below) ✅ Implemented
governance.security - agent/multi-agent/memory/RAG/privacy security, kill switch, SIEM export, red-team self-test (see below) ✅ Implemented
governance.data - Data Classification, Access Governance, Privacy/PII, Encryption, Isolation, DLP, Retention, Lineage, Quality, Lifecycle, RAG Data Governance, AI Data Access Control (see below) ✅ Implemented
governance.compliance - general-purpose requirement/evidence register (see below) ✅ Implemented
governance.responsibleai - AI Risk Management, Human Oversight & Accountability, Transparency & Explainability, Fairness & Bias, AI Safety & Reliability, AI Governance & Compliance (see below) ✅ Implemented
governance.finops - Cost Monitoring & Visibility, Cost Allocation & Attribution, Budget & Cost Controls, LLM/Model Cost Optimization, Resource Optimization, Cost Forecasting & Reporting (see below) ✅ Implemented
resilience - High Availability, Fault Tolerance, Retry & Timeout Management, Circuit Breaker & Bulkhead, Fallback & Recovery, State Checkpointing & Resume, Disaster Recovery, Capacity & Load Management (see below) ✅ Implemented
observability - Distributed Tracing (OpenTelemetry -> Jaeger), Application & Infrastructure Metrics (OpenTelemetry -> Prometheus), LLM/Agent/RAG/Tool Observability, Logs & Events (Postgres), Alerting & Anomaly Detection, Correlation & RCA, Grafana dashboard provisioning (see below) ✅ Implemented
monitoring - Health Monitoring, Performance Monitoring, AI/Agent Monitoring, Quality Monitoring, Cost Monitoring, Security/Guardrail Monitoring, Alerting & Incident Management (PagerDuty + Grafana dashboard) (see below) ✅ Implemented
core - agent/tool base classes, orchestrator ⏳ Planned

A naming note, not a contradiction: evaluation.memory and the top-level memory module are different things. evaluation.memory measures something (was a memory retrieval accurate/consistent?) from data you already collected. The top-level memory module described below is the live storage layer - the thing evaluation.memory would be measuring. Same relationship for evaluation.security (still planned as a top-level module) vs. the eventual live security enforcement layer.

Prerequisites

This library is a client, not a server. Before any of the examples below will work, you need a LiteLLM proxy already running somewhere reachable - agentic_ai.gateway never installs, starts, stops, or otherwise manages that process for you. Set it up once:

1. Install LiteLLM's proxy (a separate package from this library):

pip install 'litellm[proxy]'

2. Register at least one model. Create litellm_config.yaml - this example routes the model name gpt-4o-mini to OpenAI, reading the real provider key from an environment variable (never hardcode it in the YAML):

model_list:
  - model_name: gpt-4o-mini
    litellm_params:
      model: openai/gpt-4o-mini
      api_key: os.environ/OPENAI_API_KEY

Any provider LiteLLM supports works the same way - Anthropic, Azure OpenAI, Bedrock, a local Ollama model, etc.; only litellm_params changes. See LiteLLM's own docs for the full provider list.

3. Set the real provider key and start the proxy:

export OPENAI_API_KEY=sk-...
litellm --config litellm_config.yaml --port 4000

4. Confirm it's actually up before writing any Python against it:

curl http://localhost:4000/health/liveliness
# -> "I'm alive!"

If that curl fails, nothing below will work either - fix connectivity to the proxy first; agentic_ai.gateway's errors will otherwise (correctly) just tell you the same thing: it can't reach http://localhost:4000.

Only once you have a real, running, reachable LiteLLM proxy do the examples below have anything to talk to.

Quickstart: LLM Gateway

1. Connect to it

from agentic_ai.gateway import LiteLLMGateway

# No arguments needed for the common case: connects to
# http://localhost:4000, LiteLLM's own default port.
gateway = LiteLLMGateway()

reply = gateway.complete(
    model="gpt-4o-mini",  # must be registered on your proxy, e.g. in litellm_config.yaml
    messages=[
        {"role": "system", "content": "You are a concise assistant."},
        {"role": "user", "content": "Name three benefits of distributed tracing."},
    ],
)
print(reply)

2. Configuring host, port, and auth

from agentic_ai.gateway import LiteLLMGateway

# Custom port - your proxy isn't on LiteLLM's default 4000
gateway = LiteLLMGateway(port=5001)

# Custom host and port - a proxy running elsewhere on your network
gateway = LiteLLMGateway(host="litellm.internal", port=8080)

# Full base_url - anything host/port can't express (TLS, a path prefix)
gateway = LiteLLMGateway(base_url="https://litellm.example.com/proxy")

# A proxy that requires a virtual key
gateway = LiteLLMGateway(api_key="sk-...")  # resolve this from your own
                                             # secrets store - the gateway
                                             # module doesn't fetch it for you

3. The full response, not just the text

complete() is a convenience wrapper around chat_completion(), which returns the full OpenAI-compatible response body (usage, finish_reason, etc.) when you need more than just the message content:

result = gateway.chat_completion(
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": "Summarize this in one sentence: ..."}],
    temperature=0.2,
    max_tokens=200,
)
print(result["choices"][0]["message"]["content"])
print(result["usage"])

4. Handling errors

The gateway never lets a raw network exception escape - callers get one of two exceptions, so "the proxy is down" and "the proxy rejected the request" are never conflated:

from agentic_ai.gateway import GatewayConnectionError, GatewayRequestError, LiteLLMGateway

gateway = LiteLLMGateway()

try:
    reply = gateway.complete("gpt-4o-mini", [{"role": "user", "content": "hi"}])
except GatewayConnectionError:
    # Nothing is listening at gateway.base_url at all - is LiteLLM
    # actually running? (see Prerequisites above)
    ...
except GatewayRequestError as e:
    # The proxy responded, but with an error (bad model name, missing
    # api_key, malformed request) - e includes the proxy's own message.
    print(e)

5. Cleaning up

LiteLLMGateway holds an open HTTP connection pool; close it when you're done, or use it as a context manager:

with LiteLLMGateway() as gateway:
    reply = gateway.complete("gpt-4o-mini", [{"role": "user", "content": "hi"}])
# connection pool closed automatically here

6. LLM Audit

from agentic_ai.gateway.wrappers import AuditedLiteLLMGateway

audited = AuditedLiteLLMGateway(gateway, sink=lambda e: logger.info("llm", extra=e.model_dump()))
audited.chat_completion("gpt-4o-mini", messages)  # event carries model/latency/token usage - never prompt or response content

See Governance's Audit section for wiring this into a durable, hash- chained log alongside every other module's audit wrapper.

Evaluation

A complete production evaluation surface for single- and multi-agent AI systems - 48 metrics across 9 categories, organized one folder per category under agentic_ai.evaluation:

Category Import Measures
Agent agentic_ai.evaluation.agent Task Success/Correctness, Planning, Reasoning, Execution, Recovery, Autonomy, Loops, Lifecycle
LLM agentic_ai.evaluation.llm Response Correctness, Groundedness, Hallucination Rate, Instruction Following, Safety/Policy Violation, Latency/Tokens/Cost
Tools agentic_ai.evaluation.tools Selection/Argument Accuracy, Success/Failure Rate, Unnecessary Calls, Latency
Multi-Agent agentic_ai.evaluation.multi_agent Routing, Delegation, Handoff, Coordination, Duplicate Work
RAG agentic_ai.evaluation.rag Recall@K, Context Relevance, Groundedness, Citation Accuracy
Security agentic_ai.evaluation.security Prompt Injection, Unauthorized Execution, PII/Cross-Tenant Leakage, Authorization Violations
Platform agentic_ai.evaluation.platform Error Rate, Timeout Rate, Cost per Successful Task, SLA Compliance
Memory agentic_ai.evaluation.memory Retrieval Accuracy, Consistency
Drift agentic_ai.evaluation.drift Statistical (z-score) drift on Success/Correctness/Hallucination/Latency/Cost

Every category is deterministic, LLM-judged, or a documented mix of both - deterministic metrics need no LLM call at all (they read fields you already populated); judged metrics reuse the same LLMJudge from agentic_ai.evaluation.core, built on the gateway above, nothing else.

Deterministic - no LLM call needed

from agentic_ai.evaluation.agent import AgentTrace, compute_task_execution

traces = [
    AgentTrace(run_id="r1", task="find backend jobs", task_succeeded=True),
    AgentTrace(run_id="r2", task="find backend jobs", task_succeeded=False),
    AgentTrace(run_id="r3", task="find backend jobs", task_succeeded=True),
]
metrics = compute_task_execution(traces)
print(metrics.success_rate)  # 0.6666666666666666

LLM-judged - needs a gateway, same one as above

from agentic_ai.evaluation import LLMJudge
from agentic_ai.evaluation.llm import LLMCall, judge_response_correctness
from agentic_ai.gateway import LiteLLMGateway

judge = LLMJudge(LiteLLMGateway(), model="gpt-4o-mini")
call = LLMCall(call_id="c1", model="gpt-4o-mini", prompt="What is 2+2?", response="4")

result = judge_response_correctness(judge, call)
print(result.correct, result.score)

Every judge_*() function across every category takes an optional system_prompt override - the built-in DEFAULT_* rubric is a real, usable starting point, not the only valid one for every domain:

from agentic_ai.evaluation.llm import judge_response_correctness

legal_rubric = "You are a strict legal-domain correctness judge. ..."
result = judge_response_correctness(judge, call, system_prompt=legal_rubric)

Everything at once, persisted, compared over time

Agent Evaluation ties every deterministic + judged category together into one report, storable and diffable:

from agentic_ai.evaluation.agent import evaluate, JSONLEvaluationStore, compare

report = evaluate(traces, judge=judge)  # runs every computable category
store = JSONLEvaluationStore("eval_runs.jsonl")
store.save(report)

baseline = store.list_runs(limit=2)[1]
regressions = compare(baseline, report)  # direction-aware: knows failure_rate up is bad

For statistical drift across many runs over time (not just two points), see agentic_ai.evaluation.drift.compute_drift() and its five named wrappers (compute_task_success_drift, compute_correctness_drift, compute_hallucination_drift, compute_latency_drift, compute_cost_drift).

Every category's own trace/call shape

agent, llm, multi_agent, rag, security, and memory each have their own input model (AgentTrace, LLMCall, MultiAgentTrace, RAGQuery, AuthorizationCheck/TenantDataCheck, MemoryRetrieval) - populate the one your category needs from your own agent's logging; nothing in this library runs an agent or a retriever for you, it only evaluates the record you hand it.

Memory & State

Ten memory types, each a small facade bound to a scope (a session id, an agent id, a namespace) that knows its own purpose and picks sensible defaults - backed by your choice of in-memory, file, SQLite, Redis, Postgres (+pgvector), or Qdrant. No setup needed for local development; pass a URL when you're ready for something durable.

Facade Import Backs
SessionMemory agentic_ai.memory.SessionMemory Data scoped to one conversation/session
AgentStateMemory agentic_ai.memory.AgentStateMemory An agent's own operating state across turns
ShortTermMemory agentic_ai.memory.ShortTermMemory Recent context that outlives a single call
WorkingMemory agentic_ai.memory.WorkingMemory Scratch space for one in-flight task
LongTermMemory agentic_ai.memory.LongTermMemory Durable facts kept across sessions
SemanticMemory agentic_ai.memory.SemanticMemory Facts retrieved by meaning (vector search)
EpisodicMemory agentic_ai.memory.EpisodicMemory Past events/experiences, recallable by similarity
ProceduralMemory agentic_ai.memory.ProceduralMemory Versioned rules/workflows/operating procedures
DocumentMemory agentic_ai.memory.DocumentMemory Large source material (PDFs, contracts) + chunk search
SharedMemory agentic_ai.memory.SharedMemory A blackboard multiple agents read/write together

Zero-setup quickstart

from agentic_ai.memory import SessionMemory

session = SessionMemory("session-42")  # defaults to an in-process InMemoryStore
session.set("last_intent", "book_flight", ttl_seconds=1800)
print(session.get("last_intent").value)  # "book_flight"

Choosing a backend: just pass a URL

Every key/value facade accepts either an already-constructed store (full control - store=RedisStore(...), or a wrapper-composed one, see below) or a plain shorthand - pick exactly one:

from agentic_ai.memory import SessionMemory, LongTermMemory, AgentStateMemory

SessionMemory("session-42", redis_url="redis://localhost:6379/0")
LongTermMemory("user-123", postgres_url="postgresql://user:pass@localhost:5432/mydb")
AgentStateMemory("agent-7", sqlite_path="agent_state.db")
LongTermMemory("user-123", file_path="longterm.json")  # zero-setup but persisted to disk

redis_url/postgres_url need the matching install extra:

pip install 'enterprise-agentic-ai-framework[redis]'
pip install 'enterprise-agentic-ai-framework[postgres]'
pip install 'enterprise-agentic-ai-framework[qdrant]'
pip install 'enterprise-agentic-ai-framework[memory]'  # all three

Each facade connects and verifies immediately (a real ping / schema init) - a bad URL fails fast in the constructor, not on some later, unrelated call. This library is a client for all of these, never a process manager: deploy Redis/Postgres/Qdrant yourself, same rule as the LLM gateway above.

Semantic, episodic, and document memory (vector-backed)

Embedding generation is always your job - these facades store and search vectors, they never call an embedding model themselves:

from agentic_ai.memory import SemanticMemory

memory = SemanticMemory("user-123", qdrant_url="http://localhost:6333", embedding_dim=1536)
memory.remember("pref-1", "prefers window seats", embedding=embed("prefers window seats"))
results = memory.recall(embed("seating preference"), top_k=3)
print(results[0].record.text, results[0].score)

EpisodicMemory and DocumentMemory combine a plain store (the log / the raw document) with a vector index (similarity recall / chunk search) - pass both explicitly, since a log store and a vector index rarely share connection details:

from agentic_ai.memory import EpisodicMemory
from agentic_ai.memory.stores.sqlite_store import SQLiteStore
from agentic_ai.memory.vector_stores.qdrant_store import QdrantVectorStore

episodes = EpisodicMemory(
    "agent-7",
    store=SQLiteStore("episodes.db"),
    vector_store=QdrantVectorStore(url="http://localhost:6333", embedding_dim=1536),
)
episodes.log_episode("ep-1", "deploy failed: dependency X unavailable", embedding=embed(...))
episodes.recall_similar(embed("deployment failure"), top_k=3)

ProceduralMemory is automatically versioned - every overwrite keeps its prior value retrievable:

from agentic_ai.memory import ProceduralMemory

procedures = ProceduralMemory("support-bot", postgres_url="postgresql://...")
procedures.set("refund_policy", {"max_days": 30, "requires_receipt": True})
procedures.get_history("refund_policy")  # every prior version, oldest first

Governance, security, versioning, checkpointing, audit

Cross-cutting concerns are wrappers that compose onto any store, not sixteen separate storage systems:

from agentic_ai.memory.stores.redis_store import RedisStore
from agentic_ai.memory.wrappers import Actor, GovernedStore, RetentionPolicy, SecureStore
from agentic_ai.memory.core.models import MemoryType

base = RedisStore(url="redis://localhost:6379/0")

governed = GovernedStore(base, RetentionPolicy(
    default_ttl_seconds={MemoryType.SESSION: 1800},
    require_consent=True,
))
governed.set("session-42", "k", "v", memory_type=MemoryType.SESSION, consent=True)

secure = SecureStore(base, enforce_tenant_prefix=True)
actor = Actor(actor_id="u1", roles=["admin"], tenant_id="tenantA")
secure.set(actor, "tenantA:session-42", "k", "v")  # raises AccessDeniedError outside tenantA

checkpoint()/restore() snapshot and roll back a whole scope; VersionedStore (what ProceduralMemory uses internally) keeps a history on every write; AuditedStore emits an event to a sink you provide for every operation, success or failure. All five live in agentic_ai.memory.wrappers and take any MemoryStore - stack as many as you need.

One caveat: keys, not just types, need to be distinct

Every backend keys a record by (scope, key) only - memory_type is stored on the record for filtering, not as part of the write key. Two facades of different types that share both the same scope and the same key on the same store will overwrite each other, same as two dict writes to the same key would. In practice this is rarely an issue - one scope with many distinct keys across several facade types is a normal, safe pattern (list()/clear() on each facade only ever touch its own memory_type).

Context Engineering

Building the actual runtime context for one LLM call - the four pillars (Write, Select, Compress, Isolate) plus one core layer that ties them together: assemble(), the single function that takes whatever candidate context you've gathered and produces a budget- fitted, ordered, cache-boundary-marked result.

Everything in select/compress/isolate operates on plain ContextItems - a small model carrying content, its source (provenance), a priority, an optional relevance score, and a trust level - so every stage composes through the same shape instead of each pillar inventing its own.

Assembly - the core entry point

from agentic_ai.context import assemble, ContextItem, ContextBudget

items = [
    ContextItem(id="sys", section="system", role="system", source="system_prompt",
                content="You are a booking assistant.", priority=1.0, cacheable=True),
    ContextItem(id="turn", section="conversation", source="conversation",
                content="Book me a flight to Denver.", priority=0.95),
]
budget = ContextBudget(max_tokens=4000, reserved_for_output=1000)
result = assemble(items, budget, section_order=["system", "memory", "tools", "conversation"])

print(result.total_tokens)
print([i.id for i in result.excluded])   # what got left out, and why - Context Observability
messages = result.to_messages()          # ready for agentic_ai.gateway.chat_completion(messages=...)

assemble() handles budget packing (drops lowest-priority items first, per-section limits respected), ordering, conflict resolution (two items sharing a metadata["conflict_key"] with different content - newest wins by default), and cache-boundary marking (a cacheable=True item only keeps that flag while it's part of an unbroken cacheable prefix, since prompt caching only pays off on a shared, stable run of leading content). Pass allow_partial=False to raise ContextBudgetExceededError instead of silently dropping anything.

Write - Scratchpad + Memory

Scratchpad is new: ephemeral, ordered notes for one run. "Memories" - the part of Write meant to outlive the run - is agentic_ai.memory itself; nothing here wraps it, there's nothing to add:

from agentic_ai.context.write import Scratchpad

pad = Scratchpad("run-42", redis_url="redis://localhost:6379/0")  # same backend shorthand as agentic_ai.memory
pad.write("tried endpoint A, got a 404")
pad.write("trying endpoint B next")
pad.read_all()               # ordered ScratchpadEntry list
pad.to_context_items()       # ready for assemble()

Select - relevance, prioritization, grounding, freshness, routing

from agentic_ai.memory import SemanticMemory
from agentic_ai.context.select import from_vector_matches, prioritize, require_grounding, filter_stale

memory = SemanticMemory("user-123")
matches = memory.recall(embed("seating preference"), top_k=5)
items = from_vector_matches(matches, section="memory", source="memory:semantic")

grounded, _ = require_grounding(items)              # drops anything with no source
fresh, _ = filter_stale(grounded)                    # drops anything past its ttl_seconds
ranked = prioritize(fresh)                           # combines priority + relevance_score into one ranking

select_by_relevance() also ships a basic, dependency-free keyword scorer for candidates that didn't come from a vector search; route() fans a query out across several named sources (memory, a RAG index, a tools catalog) and merges the results.

Compress - trim, summarize, rolling summary

from agentic_ai.context.compress import trim_to_budget, summarize_items, update_rolling_summary, RollingSummaryState

trimmed = trim_to_budget(candidate_items, max_tokens=2000)           # deterministic, no LLM call

from agentic_ai.gateway import LiteLLMGateway
gateway = LiteLLMGateway()
summary_item = summarize_items(gateway, "gpt-4o-mini", old_turns)     # LLM-based, for when trimming would cut load-bearing info

state = RollingSummaryState()
state = update_rolling_summary(gateway, "gpt-4o-mini", state, all_turns, keep_recent=10)
# keeps the last 10 turns verbatim + a running summary of everything older

Isolate - trust boundaries, tenant scoping, sub-agent partitioning

from agentic_ai.context.isolate import mark_trust_boundary, wrap_untrusted, enforce_tenant_scope, partition_context

marked = mark_trust_boundary(items, trusted_sources={"system_prompt", "memory:semantic"})
safe = [wrap_untrusted(i) for i in marked]   # delimits untrusted (e.g. tool/web) content so it can't pose as an instruction

allowed, _ = enforce_tenant_scope(items, tenant_id="tenantA")

# One assemble() per sub-agent, each with its own budget - one sub-agent's
# clutter never eats another's window:
results = partition_context(
    {"researcher": researcher_items, "writer": writer_items},
    {"researcher": ContextBudget(max_tokens=4000), "writer": ContextBudget(max_tokens=4000)},
)

isolate.security is structural, not a detection engine - it doesn't classify content as an attack (that's the planned guardrails module's job), it enforces what's already known: untrusted content gets delimited, cross-tenant content gets filtered out.

Observability - what context actually went to the model

from agentic_ai.context import ContextTracer

tracer = ContextTracer("run-42", postgres_url="postgresql://...")  # same backend shorthand again
trace = tracer.record(result)   # result from assemble() above
tracer.list_traces()            # every trace recorded for this run, oldest first

Secrets Management

A client for HashiCorp Vault - static (KV v2, versioned) secrets, dynamic/leased credentials, and Transit encryption-as-a-service. Deploy Vault yourself - this is a client, never a process manager, same rule as every other real backend in this SDK.

pip install 'enterprise-agentic-ai-framework[vault]'

Connecting

from agentic_ai.secrets.vault import VaultClient

# Token auth - local dev, a CI job that already has one
vault = VaultClient(url="http://localhost:8200", token="s.xxxxx")

# AppRole - the standard machine/Workload Identity pattern
vault = VaultClient(url="https://vault.example.com:8200", role_id="...", secret_id="...")

# Kubernetes auth - reads the pod's own service account JWT, nothing
# else to configure when running in-cluster
vault = VaultClient(kubernetes_role="my-app")

# Or set nothing at all - VaultClient() reads VAULT_ADDR and, preferring
# a token if both are set, VAULT_TOKEN or VAULT_ROLE_ID+VAULT_SECRET_ID,
# the same environment variables the `vault` CLI itself uses
vault = VaultClient()

Connects and authenticates immediately - a bad token/role or an unreachable Vault fails fast in the constructor, not on some later, unrelated call. mount_point (default "secret") and namespace let one Vault serve several environments (kv-dev/kv-prod mounts, or Vault Enterprise namespaces) - Environment Isolation and Cross- environment management, without a separate abstraction.

Static secrets (KV v2) - Secret Versioning built in

vault.set_secret("db/prod", {"username": "app", "password": "s3cr3t"})
secret = vault.get_secret("db/prod")
print(secret)          # Secret(path='db/prod', version=1, keys=['password', 'username']) - never the values
print(secret.data)     # {"username": "app", "password": "s3cr3t"} - only here, on purpose

vault.set_secret("db/prod", {"username": "app", "password": "rotated"})
old = vault.get_secret("db/prod", version=1)      # any prior version, still readable
vault.rollback_secret("db/prod", to_version=1)     # writes it back as a NEW version - reversible, not a silent revert

vault.delete_secret("db/prod")                     # soft delete, recoverable
vault.destroy_secret_versions("db/prod", [1, 2])   # permanent - specific versions
vault.purge_secret("db/prod")                      # permanent - everything

Secret.__repr__/__str__ never include the actual values, only key names - a safety net for the common print(secret)/log.info("%s", secret) mistake; secret.data still gives you the real values, since that's the entire point of fetching a secret.

Dynamic/leased secrets

creds = vault.read_dynamic_secret("database/creds/readonly")  # any dynamic secrets engine - generic, not engine-specific
print(creds.lease_id, creds.lease_duration, creds.renewable)

vault.renew_lease(creds.lease_id, increment=3600)  # Secret Rotation via renewal, TTL/Expiration
vault.revoke_lease(creds.lease_id)                 # done early - revoke rather than wait out the TTL

Transit - encryption as a service

The key material never leaves Vault; this process only ever sees ciphertext:

vault.create_transit_key("app-data")
ciphertext = vault.encrypt("app-data", "a value worth encrypting")   # -> "vault:v1:..."
plaintext = vault.decrypt_text("app-data", ciphertext)                # -> "a value worth encrypting"

Sign/verify uses the same engine for content provenance instead of secrecy - proving a system prompt, a tool definition, or any other content is unmodified and actually came from whoever holds the key (Prompt Identity), without that key ever leaving Vault. Needs a signing-capable key type (key_type="ed25519" or similar - the default AES key create_transit_key() makes for encrypt/decrypt can't sign):

vault.create_transit_key("prompt-signing-key", key_type="ed25519")
signature = vault.sign("prompt-signing-key", system_prompt_text)
vault.verify("prompt-signing-key", system_prompt_text, signature)  # True/False, never raises for a bad signature

Caching and audit logging

Cross-cutting concerns are wrappers, same pattern as agentic_ai.memory's - they work over VaultClient or any future backend implementing the same small SecretsProvider protocol:

from agentic_ai.secrets import CachedSecretsProvider, AuditedSecretsProvider

cached = CachedSecretsProvider(vault, ttl_seconds=60)   # avoid hitting Vault on every call; never persisted to disk
cached.get_secret("db/prod")

def sink(event):
    logger.info("secret access", extra=event.model_dump())

audited = AuditedSecretsProvider(vault, sink=sink, actor_id="checkout-service")
audited.get_secret("db/prod")  # event carries path/action/version/outcome - never the secret's value

This client-side audit trail is distinct from Vault's own server-side audit log (enable that too - vault audit enable file file_path=... - it captures every raw API call Vault receives, independent of this SDK); this wrapper lets your application route access events into its own observability pipeline. RBAC/Policies are entirely Vault-side: whatever policy your token/AppRole/Kubernetes role carries is what this client can and can't do - a disallowed action surfaces as SecretAuthError, not a silent no-op.

Guardrails & Content Safety

Input/output validation, prompt injection and jailbreak defense, content safety, PII/DLP detection and redaction, topic restrictions, tool allow/deny-listing, rate limiting, and human-in-the-loop approval

  • all composed through one GuardrailPipeline. There's no separate "Input Guardrails" vs. "Output Guardrails" class: the same pipeline runs before the LLM call (input) or after it (output) - which one you're doing is just where you call run().

Scope note: this module owns detection and enforcement at the content layer. Full RBAC/tenant authorization lives in agentic_ai.memory's SecureStore and the future governance module; untrusted-content isolation and grounding checks are agentic_ai.context.isolate and agentic_ai.context.select.grounding; encryption and workload identity are agentic_ai.secrets.vault. Guardrails composes with those, it doesn't re-implement them.

The pipeline

A rule is any Callable[[str, dict | None], list[Finding]] - every detector below already has that shape (curry in a judge with functools.partial where one's needed), and so does any custom callable you write:

from agentic_ai.guardrails import GuardrailPipeline
from agentic_ai.guardrails.detectors import detect_prompt_injection_heuristic, detect_sensitive_data

input_guard = GuardrailPipeline([detect_prompt_injection_heuristic, detect_sensitive_data], name="input")

result = input_guard.run("my email is jane@example.com, can you reset my password?")
print(result.passed)              # True - PII is sanitized, not blocked
print(result.action)              # GuardrailAction.SANITIZE
print(result.sanitized_content)   # "my email is [REDACTED_EMAIL], can you reset my password?"

GuardrailResult.passed is True for ALLOW/SANITIZE (content can proceed, possibly modified) and False for ESCALATE/BLOCK. Pass raise_on_block=True to get a GuardrailBlocked exception instead of checking result.passed yourself.

Detectors

Detector Import Mechanism
Prompt injection detect_prompt_injection_heuristic, judge_prompt_injection phrase pre-filter + LLM judge
Jailbreak detect_jailbreak_heuristic, judge_jailbreak phrase pre-filter + LLM judge
Content safety judge_content_safety LLM judge (harassment/hate, violence, sexual, self-harm, dangerous/illegal)
Topic restriction judge_topic_restriction LLM judge
PII detect_pii regex (email, phone, SSN, credit card)
Confidential data detect_confidential_data regex (AWS keys, GitHub/Slack tokens, generic API keys)

The phrase pre-filters are zero-cost and catch the obvious cases; they are not the real detector for anything subtler - pair them with the LLM-judged versions, built on agentic_ai.evaluation.LLMJudge (reused, not rebuilt - the same JSON-mode judge engine every measurement judge in this SDK already uses):

from functools import partial
from agentic_ai.evaluation import LLMJudge
from agentic_ai.gateway import LiteLLMGateway
from agentic_ai.guardrails.detectors import judge_prompt_injection, judge_content_safety

judge = LLMJudge(LiteLLMGateway(), model="gpt-4o-mini")
pipeline = GuardrailPipeline([
    detect_prompt_injection_heuristic,
    partial(judge_prompt_injection, judge),
    partial(judge_content_safety, judge),
])

Every judge function takes an optional system_prompt override, same pattern as every judge in agentic_ai.evaluation. Finding.detail never contains the matched text itself, only a safe-to-log summary and a span into your own original content - a Finding can be handed to an audit sink without a second thought.

Tool / Action guardrails

Deliberately a lightweight allow/deny-list, not a full RBAC engine:

from agentic_ai.guardrails.tools import ToolPolicy, check_tool_call

policy = ToolPolicy(allowed_tools={"search", "reset_password"}, denied_tools={"delete_account"})
result = check_tool_call(policy, "reset_password", {"user_id": "u1"}, actor="session-1")

Rate limiting and human-in-the-loop

Both reuse agentic_ai.memory for their state - same backend shorthand (redis_url, postgres_url, ...) as everywhere else in this SDK, so a limit or an approval queue is durable and shared across processes when you need it to be:

from agentic_ai.guardrails.abuse import RateLimiter
from agentic_ai.guardrails.human import ApprovalQueue

limiter = RateLimiter(limit=100, window_seconds=60, redis_url="redis://localhost:6379/0")
if not limiter.check("user-42").allowed:
    ...

queue = ApprovalQueue(postgres_url="postgresql://...")
request = queue.request_approval("wire transfer of $50,000", risk_level="critical", requested_by="agent-7")
# a separate reviewer process/UI calls queue.approve(request.request_id, resolved_by="alice")

Auditability

from agentic_ai.guardrails.wrappers import AuditedGuardrailPipeline

audited = AuditedGuardrailPipeline(input_guard, sink=lambda e: logger.info("guardrail", extra=e.model_dump()), actor_id="session-1")
audited.run(user_message)  # event carries rule/category/severity/action - never the raw content or a sensitive span

Authentication

A client for Keycloak's authentication mechanics - the "how do you prove it" layer: password/SSO/OIDC/OAuth2 grants, MFA, mTLS client- certificate auth, token issuance/validation/refresh/revocation. Not authorization: it proves who someone (or some service) is and hands back a token plus raw claims data. Interpreting those claims into a rich identity is agentic_ai.identity's job (below), built from this client's output - this module has no dependency on identity at all. Enforcing what an identity is allowed to do is a further step still, the future governance module's job, same boundary guardrails' tool allow-listing already draws.

pip install 'enterprise-agentic-ai-framework[authentication]'

Connecting and authenticating

from agentic_ai.authentication import KeycloakClient

client = KeycloakClient(
    server_url="http://localhost:8080", realm_name="my-realm",
    client_id="my-service", client_secret="...",
)

# Password grant - a user's own credentials (add totp=123456 for MFA realms)
tokens = client.authenticate(username="alice", password="...")

# client_credentials grant - Workload Identity for a service, no user involved
tokens = client.authenticate_service_account()

print(tokens.access_token, tokens.expires_at, tokens.is_expired)  # tokens.__repr__ never shows the actual strings

Connects and confirms the realm exists immediately - a bad URL or unknown realm fails fast in the constructor, not on some later, unrelated call. Pass client_cert/client_key (PEM file paths) instead of/alongside client_secret for Certificate Authentication (mTLS) to Keycloak itself.

Validating a token

raw_claims = client.decode_token(tokens.access_token)   # local, offline - verifies signature against Keycloak's JWKS; returns a plain dict
status = client.introspect(tokens.access_token)          # asks Keycloak directly - catches server-side revocation decode_token() can't see
print(status.active)

raw_user_info = client.get_user_info(tokens.access_token) # the userinfo endpoint; also a plain dict

decode_token()/get_user_info() deliberately return raw dicts, not identity objects - see Identity below for the typed models built from this output.

Refresh, revoke, logout, and the authorization_code flow

refreshed = client.refresh(tokens.refresh_token)
client.revoke_token(tokens.access_token)  # RFC 7009 - revokes a specific token, distinct from logout()
client.logout(tokens.refresh_token)        # ends the session via its refresh token

url = client.build_authorization_url("https://app.example.com/callback", state="xyz")
# ... redirect the user's browser to `url` - Keycloak's own hosted login
# page handles SSO/WebAuthn/FIDO2 transparently here, nothing extra to
# implement - they come back with a `code` ...
tokens = client.exchange_code_for_token(code, "https://app.example.com/callback")

Agent / Tools Identity - Token Exchange

OAuth2 Token Exchange (RFC 8693) - the standards-based way to give an agent or a tool call its own distinct, scoped, attributable token derived from the original caller's, instead of every agent/tool call sharing one client's identity. Requires Keycloak's Standard Token Exchange feature enabled for the client:

agent_tokens = client.exchange_token(user_tokens.access_token, audience="downstream-service")

Auto-refresh

The tedious part of every OAuth client, done once:

from agentic_ai.authentication import TokenManager

manager = TokenManager(client, grant_type="client_credentials")
header = {"Authorization": f"Bearer {manager.get_access_token()}"}
# subsequent calls authenticate on first use, refresh near expiry, and
# fall back to a full re-authentication if the refresh token itself
# has expired - manager.invalidate() forces a fresh one, e.g. after a
# downstream 401

Auditability

from agentic_ai.authentication.wrappers import AuditedKeycloakClient

audited = AuditedKeycloakClient(client, sink=lambda e: logger.info("auth", extra=e.model_dump()))
audited.authenticate(username="alice", password="...")  # event carries grant_type/username/outcome - never the token or password

Identity

The claims/data layer, built entirely from plain dicts - typically agentic_ai.authentication's decode_token()/get_user_info() output, or any other OIDC-compatible source. No dependency on authentication, or on python-keycloak being installed at all.

from agentic_ai.authentication import KeycloakClient
from agentic_ai.identity import TokenClaims, UserInfo

auth = KeycloakClient(server_url="...", realm_name="my-realm", client_id="my-service", client_secret="...")
tokens = auth.authenticate(username="alice", password="...")

claims = TokenClaims.from_claims(auth.decode_token(tokens.access_token))
print(claims.subject, claims.username, claims.realm_roles)
print(claims.has_realm_role("admin"), claims.has_client_role("my-service", "editor"))

info = UserInfo.from_response(auth.get_user_info(tokens.access_token))

Tenant Identity Isolation

Keycloak has no built-in "tenant" claim - if your deployment adds one via a custom protocol mapper, TokenClaims picks it up automatically (claims.tenant_id), and require_tenant() enforces it, same pattern as memory.wrappers.SecureStore's enforce_tenant_prefix and guardrails.isolate.enforce_tenant_scope:

from agentic_ai.identity import require_tenant, TenantMismatchError

require_tenant(claims, "tenant-A")  # raises TenantMismatchError on any other tenant
# a differently-named claim: require_tenant(claims, "org-42", claim_name="org_id")

If your deployment instead models tenancy as one realm per tenant, isolation is already realm boundaries - construct a separate KeycloakClient per tenant and this helper isn't the right tool for that shape.

Governance

agentic_ai.governance is the umbrella for this SDK's policy/ compliance components, each its own subpackage rather than flattened into one namespace. authorization is implemented today (below); compliance, audit, data_governance, finops, responsible_ai, and security are scaffolded, not yet usable.

Deliberately not here: agentic_ai.identity and agentic_ai.authentication (IAM - who someone is and proving it) stay top-level siblings of this package, not nested inside it - governance.authorization consumes identity as input (user.roles), so nesting identity inside governance would put the dependency direction backwards.

Authorization

A client for Open Policy Agent's REST API - the Policy Decision Point (PDP) authorize()/evaluate() query. RBAC, ABAC, fine-grained, resource-, action-, agent-, tool-, and tenant-level authorization are all just different shapes of one generic policy query, not separate code paths - that's OPA's own design, not something this client reinvents. Nothing is hardcoded: the OPA URL, the policy path, and every piece of the authorization input are parameters you supply.

Built directly on httpx (already a base dependency, same as agentic_ai.gateway) - no new extra needed.

from agentic_ai.governance.authorization import OPAClient

opa = OPAClient(url="http://localhost:8181")  # or host="...", port=8181 - never a fixed address

Connects and verifies immediately (a real /health check) - an unreachable OPA fails fast in the constructor.

decision = opa.authorize(
    user={"roles": ["job-seeker"]},
    action="invoke",
    resource={"type": "agent", "name": "job_search"},
    context={"risk_score": 0, "business_hours": True},
    policy_path="authz/allow",  # always overridable - no assumption about your package layout
)
print(decision.allowed, decision.defined)  # defined=False means "no such policy", not "policy said no"

opa.authorize(..., raise_on_deny=True)  # raises AuthorizationDenied instead of checking .allowed yourself

# Any result shape - not just plain allow/deny:
decision = opa.evaluate("authz", {"user": ..., "action": ..., "resource": ...})
print(decision.result)  # e.g. {"allow": true, "risk_threshold": 2}

Dynamic context - never a static risk_score/business_hours

from agentic_ai.governance.authorization.context import build_context

context = build_context(
    risk_score=0,                       # a plain int, or a zero-arg callable computed fresh per call
    business_hours_start=9, business_hours_end=17,  # default 0-24 (wide open) - narrow explicitly, never assumed
    tenant_id="tenant-A",                # any **extra merges straight into the context dict
)

Wire a real risk score from agentic_ai.guardrails' own audit trail instead of a fixed number:

from functools import partial
from agentic_ai.governance.authorization.risk import count_recent_violations

risk_score = partial(count_recent_violations, recent_events, actor_id=user_id, window_seconds=3600)
context = build_context(risk_score=risk_score)

Policy management

opa.upload_policy("authz", rego_source)
opa.list_policies()
opa.get_policy("authz")
opa.delete_policy("authz")

Auditability

from agentic_ai.governance.authorization.wrappers import AuditedOPAClient

audited = AuditedOPAClient(opa, sink=lambda e: logger.info("authz", extra=e.model_dump()))
audited.authorize(user=..., action=..., resource=...)  # event carries subject/action/resource/allowed - context excluded unless include_context=True

What's already covered elsewhere, not rebuilt here

RBAC (agentic_ai.identity.TokenClaims), Delegated Authorization (agentic_ai.authentication.KeycloakClient.exchange_token()), Tenant Authorization (agentic_ai.identity.require_tenant()), Tool Authorization (agentic_ai.guardrails.tools.ToolPolicy), and Human Approval (agentic_ai.guardrails.human.ApprovalQueue) already exist - this module composes with them. Transaction Limits and Data Authorization need no special code - they're just more fields in resource/context for your policy to check. Least Privilege is a principle for how you write your Rego policies, not something a client enforces.

Audit

Every audit wrapper across this SDK (memory, secrets, guardrails, authentication, governance.authorization, gateway) hands you an event via a sink callback and deliberately leaves storage to you - AuditLog is a real, durable place to put them: hash-chained (each record links to the one before it, so tampering, deletion, or reordering is detectable), backed by agentic_ai.memory (same "just pass a url" pattern as everywhere else - no new dependency).

from agentic_ai.governance.audit import AuditLog

log = AuditLog("platform", redis_url="redis://localhost:6379/0")  # or in-memory/file/sqlite/postgres - same shorthand as everywhere else

Wire any existing wrapper's sink straight into it with the matching adapter:

from agentic_ai.governance.audit.adapters import guardrail_sink, llm_sink
from agentic_ai.guardrails.wrappers import AuditedGuardrailPipeline
from agentic_ai.gateway.wrappers import AuditedLiteLLMGateway

audited_pipeline = AuditedGuardrailPipeline(input_guard, sink=guardrail_sink(log))
audited_gateway = AuditedLiteLLMGateway(gateway, sink=llm_sink(log))  # LLM Audit - model, latency, token usage, never prompt/response content

memory_sink, secret_sink, guardrail_sink, authentication_sink, authorization_sink, and llm_sink cover every existing audit wrapper; log_approval_decision(log, resolved_request) is a convenience for agentic_ai.guardrails.human.ApprovalQueue (it returns the resolved decision directly rather than streaming through a callback). Agent, Multi-Agent, Tool, Data/RAG, and Business- Transaction audit have no dedicated adapter - this SDK doesn't itself execute those, so call log.append(source_module=..., action=..., outcome=..., actor_id=..., details=...) directly.

records = log.list_records(actor_id="user-1", since=one_hour_ago)
log.verify_chain()  # raises AuditIntegrityError if anything was tampered with, deleted, or reordered

Security

One submodule per domain - agentic_ai.governance.security.<domain>, each its own import (several would collide on names flattened into one namespace). llm and tool are thin, documented re-exports of agentic_ai.guardrails (that's where the real detection/allow-listing logic lives); every other submodule is new. Not here at all - genuinely not something a Python client library can provide: Network, Infrastructure, Cloud, and OS-level Runtime Security, Supply Chain Security, and Vulnerability Management (SAST/DAST/scanning/ pentesting).

# Agent Security - capability restrictions + autonomous-step limits (new)
from agentic_ai.governance.security.agent import AgentSecurityPolicy, check_agent_action

policy = AgentSecurityPolicy(allowed_actions={"search", "book"}, max_autonomous_steps=10)
result = check_agent_action(policy, "search", step_count=3, agent_id="agent-7")

# Multi-Agent Security - trust boundaries between agents (new)
from agentic_ai.governance.security.multi_agent import AgentTrustPolicy, require_trusted_agent

trust = AgentTrustPolicy(trusted_agent_ids={"orchestrator", "researcher"})
require_trusted_agent(trust, sender_agent_id)  # raises UntrustedAgentError otherwise

# Memory Security - Memory Poisoning Protection: screen content before it's written (new)
from agentic_ai.governance.security.memory import ScreenedStore

screened = ScreenedStore(redis_store, input_guard)  # any MemoryStore + any GuardrailPipeline
screened.set("agent-7", "learned_fact", tool_output_text)  # raises MemoryWriteBlocked if the pipeline blocks it

# RAG Security - screen retrieved documents the same way input/output is screened (new)
from agentic_ai.governance.security.rag import screen_retrieved_document

result = screen_retrieved_document(input_guard, retrieved_document_text, source="knowledge_base/doc1")

# Privacy Security - PII redaction + consent + retention as one store (new)
from agentic_ai.governance.security.privacy import PrivacyStore
from agentic_ai.memory.wrappers.governance import RetentionPolicy

privacy_store = PrivacyStore(redis_store, RetentionPolicy(require_consent=True))
privacy_store.set("user-1", "note", "contact jane@example.com", consent=True)  # -> "[REDACTED_EMAIL]"

# Incident Response - kill switch (new)
from agentic_ai.governance.security.kill_switch import KillSwitch

kill_switch = KillSwitch("platform", redis_url="redis://localhost:6379/0")  # shared across every process
kill_switch.check()  # raises KillSwitchEngaged if someone has engaged it - call this at the start of any haltable operation
kill_switch.engage(reason="prompt injection wave detected", actor_id="oncall-1")

# Security Monitoring - SIEM export in CEF (new)
from agentic_ai.governance.security.siem import export_cef

cef_lines = export_cef(log.list_records())  # ready to ship to ArcSight/Splunk/QRadar

# Red Teaming - self-test your own guardrails against known adversarial payloads (new)
from agentic_ai.governance.security.redteam import run_red_team, pass_rate

results = run_red_team(input_guard)  # DEFAULT_PAYLOADS, or pass your own `cases`
print(pass_rate(results))

Data Governance & Security

One submodule per domain - agentic_ai.governance.data.<domain>. classification, access, ai_access, lineage, quality, lifecycle, and rag are new code. privacy, dlp, encryption, isolation, and retention are thin, documented re-exports of where the real implementation already lives (agentic_ai.guardrails.detectors.pii, agentic_ai.secrets.vault, agentic_ai.identity, agentic_ai.memory.wrappers) - not duplicated, just made discoverable under the Data Governance name. Not here at all - genuinely not something a Python client library can provide: physical data residency enforcement, database-level column encryption/masking, and full ETL-grade data-quality profiling.

# Data Classification - the sensitivity tier everything else keys off of (new)
from agentic_ai.governance.data.classification import DataClassification, ClassificationPolicy, HandlingRequirements

policy = ClassificationPolicy(requirements={
    DataClassification.RESTRICTED: HandlingRequirements(
        minimum_role="admin", requires_encryption=True, default_retention_seconds=3600,
    ),
})

# Data Access Governance - does this actor's role meet the classification's minimum (new)
from agentic_ai.governance.data.access import check_data_access

result = check_data_access(policy, DataClassification.RESTRICTED, {"employee"}, actor_id="user-1")
result.passed  # False - "employee" doesn't meet the "admin" minimum_role for RESTRICTED data

# AI Data Access Control - the same check, named for an agent/model caller (new)
from agentic_ai.governance.data.ai_access import check_ai_data_access

check_ai_data_access(policy, DataClassification.RESTRICTED, {"admin"}, agent_id="agent-1").passed  # True

# Data Privacy & PII / Data Loss Prevention - both bridge to agentic_ai.guardrails.detectors.pii
from agentic_ai.governance.data.privacy import detect_sensitive_data, redact

findings = detect_sensitive_data("contact jane@example.com")
redact("contact jane@example.com", findings)  # -> "contact [REDACTED_EMAIL]"

# Data Encryption - thin pass-through to a VaultClient-shaped object, no hvac import forced on you
from agentic_ai.governance.data.encryption import encrypt_data, decrypt_data

ciphertext = encrypt_data(vault_client, "app-key", "sensitive-value")
decrypt_data(vault_client, "app-key", ciphertext)  # -> "sensitive-value"

# Data Isolation - structural tenant isolation, bridges to agentic_ai.memory.wrappers.security.SecureStore
from agentic_ai.governance.data.isolation import Actor, SecureStore
from agentic_ai.memory.stores.in_memory import InMemoryStore

secure_store = SecureStore(InMemoryStore(), enforce_tenant_prefix=True)
secure_store.set(Actor(actor_id="u1", tenant_id="tenant-a"), "tenant-a:docs", "k1", "v1")  # a tenant literally cannot reach another tenant's scope

# Data Retention & Deletion - bridges to agentic_ai.memory.wrappers.governance.GovernedStore
from agentic_ai.governance.data.retention import GovernedStore, RetentionPolicy
from agentic_ai.memory.core.models import MemoryType

governed_store = GovernedStore(InMemoryStore(), RetentionPolicy(default_ttl_seconds={MemoryType.SESSION: 3600}))
governed_store.set("scope1", "k1", "v1", memory_type=MemoryType.SESSION)  # expires in 3600s by default

# Data Lineage - what data descended from what, distinct from governance.audit's who-did-what (new)
from agentic_ai.governance.data.lineage import DataLineage

lineage = DataLineage("platform", redis_url="redis://localhost:6379/0")  # or in-memory/file/sqlite/postgres, same shorthand as everywhere else
lineage.record("raw-doc-1", transformation="ingest")
lineage.record("summary-1", source_ids=["raw-doc-1"], transformation="summarize")
lineage.trace_ancestry("summary-1")  # -> [summary-1, raw-doc-1], closest ancestor first

# Data Quality - a lightweight rule-runner, not a full ETL/data-quality platform (new)
from agentic_ai.governance.data.quality import required_fields_rule, run_quality_checks

rule = required_fields_rule("has_name_email", ["name", "email"])
run_quality_checks({"name": "Jane"}, [rule])  # -> [DataQualityResult(rule_name="has_name_email", passed=False, ...)]

# Data Lifecycle Management - derives retention from classification instead of configuring both separately (new)
from agentic_ai.governance.data.lifecycle import retention_policy_for

retention_policy_for(policy, {DataClassification.RESTRICTED: MemoryType.LONG_TERM})  # -> RetentionPolicy(default_ttl_seconds={LONG_TERM: 3600})

# RAG Data Governance - a retrieved document must pass content screening AND classification-based access (new)
from agentic_ai.governance.data.rag import govern_rag_retrieval

result = govern_rag_retrieval(
    input_guard, retrieved_document_text,
    classification_policy=policy, document_classification=DataClassification.INTERNAL, actor_roles={"employee"},
)

Compliance

A general-purpose evidence register - not AI-specific, since compliance requirements (SOC 2, ISO 27001, GDPR, the EU AI Act, ...) apply across a whole platform. agentic_ai.governance.responsibleai bridges this in under the "AI Governance & Compliance" name rather than duplicating a second register there.

from agentic_ai.governance.compliance import ComplianceRegister, ComplianceStatus

register = ComplianceRegister("platform", redis_url="redis://localhost:6379/0")  # or in-memory/file/sqlite/postgres, same shorthand as everywhere else
register.record("SOC 2 CC6.1", framework="SOC 2", status=ComplianceStatus.COMPLIANT, evidence="access review Q3-2026")

register.latest_status("SOC 2 CC6.1")  # the most recent record - every record() call is kept as history, not overwritten
register.require_compliant("SOC 2 CC6.1")  # raises ComplianceRequirementMissing unless the latest status is COMPLIANT

Responsible AI

One submodule per capability - agentic_ai.governance.responsibleai.<domain>. risk, explainability, and fairness are new code; oversight bridges human approval from agentic_ai.guardrails.human (accountability tracking is new); safety bridges the kill switch/timeout from agentic_ai.governance.security and judge-reliability checks from agentic_ai.evaluation (the operating-envelope check is new); compliance bridges agentic_ai.governance.compliance and agentic_ai.governance.audit. Not here at all - genuinely not something a Python client library can provide: certifying an AI system as fair, safe, or compliant in fact. This module gives you the structural tools; the judgment calls (what tier is this use case, what bias threshold is acceptable, who is actually accountable) stay yours.

# 1. AI Risk Management - classify a use case's risk tier, gate on it (new)
from agentic_ai.governance.responsibleai.risk import AIRiskTier, RiskRegister, require_permitted_tier

risk_register = RiskRegister("platform")
assessment = risk_register.record(
    "resume-screening", AIRiskTier.HIGH, rationale="automated hiring decisions",
    mitigations=["human review required"], owner="hr-ai-team",
)
require_permitted_tier(assessment, AIRiskTier.LIMITED)  # raises RiskThresholdExceeded - HIGH exceeds LIMITED

# 2. Human Oversight & Accountability - approval is agentic_ai.guardrails.human's ApprovalQueue; ownership is new
from agentic_ai.governance.responsibleai.oversight import AccountabilityRegister, ApprovalQueue

accountability = AccountabilityRegister("platform")
accountability.assign_owner("resume-screening-model", "alice@corp.com", role="model owner")
accountability.require_owner("resume-screening-model")  # raises AccountabilityRequired if nobody's on record

approvals = ApprovalQueue(scope="platform_approvals")
request = approvals.request_approval("deploy resume-screening-model v2", requested_by="alice@corp.com")
approvals.approve(request.request_id, resolved_by="bob@corp.com")

# 3. Transparency & Explainability - system-level documentation + per-decision evidence (new)
from agentic_ai.governance.responsibleai.explainability import SystemCard, explain_decision, judge_explanation_quality

card = SystemCard(
    system_name="resume-screener", version="2.0", intended_use="rank candidate resumes for recruiter review",
    limitations=["not validated outside US English resumes"], owner="hr-ai-team",
)
explanation = explain_decision(
    "decision-123", "Candidate ranked #3 due to matching 8/10 required skills.",
    evidence=["skill_match=0.8", "years_experience=5"], confidence=0.72, model="gpt-4o-mini",
)
judge_explanation_quality(judge, explanation)  # LLMJudge - flags generic/boilerplate explanations

# 4. Fairness & Bias - an LLM-judged check for one response, a deterministic metric for outcome data (new)
from agentic_ai.governance.responsibleai.fairness import judge_fairness, outcome_parity

judge_fairness(judge, model_output_text)  # is_biased, protected_attributes, confidence, reasoning
outcome_parity({"group_a": [True, True, True, False, False], "group_b": [True, False, False, False, False]})
# -> impact_ratio=0.33, passes_four_fifths_rule=False (the US EEOC's disparate-impact threshold)

# 5. AI Safety & Reliability - a structural operating-envelope check (new) + kill switch/timeout (bridged)
from agentic_ai.governance.responsibleai.safety import SafetyPolicy, check_safety_bounds, run_with_timeout, KillSwitch

policy = SafetyPolicy(max_retries=3, max_output_length=2000)
check_safety_bounds(policy, model_output_text, attempt=1)  # [] if within bounds, else violation messages

kill_switch = KillSwitch("platform", redis_url="redis://localhost:6379/0")
kill_switch.check()  # raises KillSwitchEngaged if someone has halted the platform

# 6. AI Governance & Compliance - policy evidence + audit trail, both bridged
from agentic_ai.governance.responsibleai.compliance import ComplianceRegister, ComplianceStatus, AuditLog

compliance_register = ComplianceRegister("platform_ai")
compliance_register.record("EU AI Act Art. 9", framework="EU AI Act", status=ComplianceStatus.COMPLIANT, evidence="risk management system documented")

audit_log = AuditLog("platform_ai_audit")
audit_log.append(source_module="responsibleai", action="risk_assessed", outcome="success", actor_id="alice@corp.com", details={"use_case": "resume-screening", "tier": "high"})

FinOps

One submodule per capability - agentic_ai.governance.finops.<domain>. All new code except where it deliberately fills a gap another module's docstring already named (LLMJudge's cost computation). CostLedger and BudgetRegister persist via agentic_ai.memory, same "just pass a url" pattern as every other real backend in this SDK - point them at postgres_url for durable, queryable, BI-joinable cost data; that's the backend this module is built to be used with in production, not just one option among several. Not here at all - genuinely not something a Python client library can do to actual cloud/GPU/database infrastructure: real resource optimization requires your cloud provider's own cost-optimization API, or a human. recommend_rightsizing() below is the honest, generic arithmetic that stands in for it.

# 1. Cost Monitoring & Visibility - a durable, queryable ledger across every resource type
from agentic_ai.governance.finops.ledger import CostLedger
from agentic_ai.governance.finops.models import ResourceType

ledger = CostLedger("platform", postgres_url="postgresql://user:pass@localhost:5432/finops")  # or in-memory/redis/sqlite/file for smaller deployments
ledger.record_cost(ResourceType.LLM, 1.25, quantity=5000, unit="tokens", dimensions={"team": "growth", "model": "gpt-4o-mini", "tenant_id": "acme"})
ledger.record_cost(ResourceType.GPU, 4.00, quantity=2, unit="gpu_hours", dimensions={"team": "ml-platform"})
ledger.total_cost()  # -> 5.25

# 2. Cost Allocation & Attribution - group the same ledger by whatever dimension matters
from agentic_ai.governance.finops.attribution import attribute_costs

attribute_costs(ledger, "team")  # -> {"growth": 1.25, "ml-platform": 4.00}

# 3. Budget & Cost Controls - a spending limit scoped to a dimension filter, checked against the ledger
from agentic_ai.governance.finops.budget import BudgetRegister

budgets = BudgetRegister("platform", postgres_url="postgresql://user:pass@localhost:5432/finops")
growth_budget = budgets.create("growth-team-monthly", 100.0, scope={"team": "growth"}, alert_threshold_pct=0.8)
budgets.check(growth_budget, ledger, raise_on_exceeded=True)  # raises BudgetExceeded once spend crosses limit_usd

# 4. LLM / Model Cost Optimization - the per-model pricing table agentic_ai.evaluation.LLMJudge's own docstring defers to this module
from agentic_ai.governance.finops.pricing import ModelPricing, PricingTable, compute_llm_cost, estimate_cache_savings

pricing = PricingTable(rates={"gpt-4o-mini": ModelPricing(input_cost_per_1k=0.00015, output_cost_per_1k=0.0006)})
compute_llm_cost(pricing, "gpt-4o-mini", prompt_tokens=1000, completion_tokens=500)  # -> 0.00045
estimate_cache_savings(pricing, "gpt-4o-mini", 1000, 500, cache_hit_rate=0.4)  # -> 0.00018, a planning number, not a cache

# 5. Resource Optimization - a deterministic rightsizing recommendation from utilization data you supply
from agentic_ai.governance.finops.resource import ResourceTier, UtilizationSample, recommend_rightsizing

tiers = [ResourceTier(name="small", capacity=4, cost_per_hour=0.5), ResourceTier(name="medium", capacity=8, cost_per_hour=1.0), ResourceTier(name="large", capacity=16, cost_per_hour=2.0)]
sample = UtilizationSample(current_tier="large", avg_utilization_pct=20, peak_utilization_pct=30)
recommend_rightsizing(sample, tiers, target_headroom_pct=20.0)  # -> recommends "medium", saves $1.00/hr

# 6. Cost Forecasting & Reporting - a least-squares trend projection + a grouped report over the ledger
from agentic_ai.governance.finops.forecasting import cost_report, forecast_costs

forecast_costs([10.0, 12.0, 14.0, 16.0, 18.0], periods_ahead=3)  # -> forecast=[20.0, 22.0, 24.0], trend_per_period=2.0
cost_report(ledger, group_by="team")  # -> total_usd=5.25, breakdown={"growth": 1.25, "ml-platform": 4.00}

Resilience & Reliability

One submodule per capability - agentic_ai.resilience.<domain>. high_availability, fault_tolerance, circuit_breaker, fallback, and disaster_recovery are new code; retry bridges agentic_ai.governance.security.runtime's timeout for its timeout half; checkpoint bridges agentic_ai.memory.wrappers.checkpointing (not duplicated - snapshot/restore is exactly what "resume an interrupted workflow" needs); capacity bridges agentic_ai.guardrails.abuse.RateLimiter for rate limiting. Not here at all - genuinely not something a Python client library can do: actually running redundant infrastructure, multi-zone/region failover, autoscaling, or a cloud provider's own backup service. Every module below gives you the structural primitive real resilience engineering is built from - the infrastructure underneath stays yours to provide.

# 1. High Availability - route around an unhealthy endpoint using a health check you supply (new)
from agentic_ai.resilience.high_availability import Endpoint, select_healthy_endpoint

endpoints = [Endpoint(name="primary", priority=0), Endpoint(name="secondary", priority=1)]
select_healthy_endpoint(endpoints, health_check=lambda e: ping(e))  # raises NoHealthyEndpointError if none are healthy

# 2. Fault Tolerance & Failure Handling - classify an exception so retry/circuit-breaker/fallback share one answer (new)
from agentic_ai.resilience.fault_tolerance import classify_failure

classify_failure(ConnectionError("connection reset"))  # -> FailureCategory.TRANSIENT

# 3. Retry & Timeout Management - bounded exponential backoff, never infinite (new) + a thread-based timeout (bridged)
from agentic_ai.resilience.retry import RetryPolicy, retry, check_iteration_limit, run_with_timeout

retry(call_llm, policy=RetryPolicy(max_attempts=3, base_delay_seconds=0.5))  # retries TRANSIENT/RATE_LIMITED/TIMEOUT, not PERMANENT
check_iteration_limit(step_count, max_iterations=50)  # raises MaxIterationsExceeded - the explicit agent-loop guard

# 4. Circuit Breaker & Bulkhead - isolate a failing dependency, cap concurrent calls to it (new)
from agentic_ai.resilience.circuit_breaker import Bulkhead, CircuitBreaker

breaker = CircuitBreaker(failure_threshold=5, recovery_timeout_seconds=30.0)
bulkhead = Bulkhead(max_concurrent=10)
breaker.call(call_vector_db)  # raises CircuitOpenError immediately once the circuit trips - no wasted retries on a dependency that's down

# 5. Fallback & Recovery - fall back through a chain of models/tools/services (new)
from agentic_ai.resilience.fallback import with_fallback

with_fallback(call_primary_model, call_backup_model, args=("summarize this",))  # raises AllFallbacksFailedError only if every candidate fails

# 6. State Checkpointing & Resume - snapshot and restore agent state, the same primitive that recovers an interrupted workflow
from agentic_ai.resilience.checkpoint import checkpoint, list_checkpoints, restore

cp = checkpoint(agent_store, "workflow-42", label="before risky step")
latest = list_checkpoints("workflow-42", checkpoint_store=agent_store)[0]  # newest first - what a resume restores from
restore(agent_store, "workflow-42", latest.checkpoint_id)

# 7. Disaster Recovery - a portable file-based backup + real RPO/RTO arithmetic against an objective you define (new)
from agentic_ai.resilience.disaster_recovery import RecoveryObjective, evaluate_rpo, export_backup, import_backup

objective = RecoveryObjective(rpo_seconds=3600, rto_seconds=600)
evaluate_rpo(objective, last_backup_at)  # True if a disaster right now would lose no more than rpo_seconds of data
export_backup(agent_store, "workflow-42", "backup.json", label="nightly")  # portable - survives the live store being lost entirely
import_backup(disaster_recovery_store, "backup.json")

# 8. Capacity & Load Management - rate limiting (bridged) + a bounded queue with a real backpressure signal (new)
from agentic_ai.resilience.capacity import BoundedQueue, RateLimiter

limiter = RateLimiter(limit=100, window_seconds=60, redis_url="redis://localhost:6379/0")  # shared correctly across replicas
queue = BoundedQueue(maxsize=1000)
queue.enqueue(task)  # raises QueueFullError immediately when at capacity, rather than blocking or growing unbounded

Observability

One submodule per capability - agentic_ai.observability.<domain>. Built entirely on real, standard backends, not this SDK's own invented formats: OpenTelemetry for both tracing and metrics, exported to Jaeger (OTLP/HTTP) and Prometheus (via opentelemetry-exporter-prometheus) respectively, with a real Grafana dashboard provisioned straight from those Prometheus metrics, and Logs & Events persisted to Postgres. Span names follow a <domain>.<action> convention (agent.<name>, llm.invoke, rag.retrieval, tool.<name>) so every capability's spans read consistently in Jaeger's UI. Install with the [observability] extra (or [tracing]/[metrics] individually).

# 1. Distributed Tracing - real OpenTelemetry spans, exported via OTLP/HTTP to Jaeger
from agentic_ai.observability.tracing import Tracer, get_current_trace_id

tracer = Tracer("my-service", otlp_endpoint="http://localhost:4318/v1/traces")
with tracer.span("agent.job_search", attributes={"agent.step_type": "orchestration"}):
    with tracer.span("llm.invoke", attributes={"llm.model": "gpt-4o-mini"}):
        ...  # nests automatically via OTel's own context propagation - no manual trace_id plumbing

# 2. Application & Infrastructure Metrics - the OpenTelemetry Metrics API, exported in real Prometheus format
from agentic_ai.observability.metrics import MetricsRegistry

metrics = MetricsRegistry("my-service")
metrics.record_request("llm", outcome="success", latency_seconds=0.42)
body, content_type = metrics.expose()  # ready for any Prometheus server's scrape config; P95/P99 via histogram_quantile()

# 3. LLM Observability - a span + metrics per call, cost attached when a PricingTable is supplied
from agentic_ai.observability.llm_observability import ObservedLiteLLMGateway
from agentic_ai.governance.finops.pricing import ModelPricing, PricingTable

pricing = PricingTable(rates={"gpt-4o-mini": ModelPricing(input_cost_per_1k=0.00015, output_cost_per_1k=0.0006)})
observed_gateway = ObservedLiteLLMGateway(gateway, tracer=tracer, metrics=metrics, pricing=pricing)
observed_gateway.chat_completion("gpt-4o-mini", messages)  # emits llm.invoke span with tokens/latency/cost + Prometheus metrics

# 4. Agent Observability - agent steps/decisions/tool calls/loops/retries/handoffs as agent.<name> spans
from agentic_ai.observability.agent_observability import trace_agent_step

with trace_agent_step(tracer, "job_search", step_type="orchestration", metrics=metrics):
    ...

# 5. RAG Observability - retrieval latency, query, retrieved sources, top-K, failures
from agentic_ai.observability.rag_observability import trace_retrieval

with trace_retrieval(tracer, "python developer remote", top_k=5, metrics=metrics) as result:
    result["sources"] = ["doc-1", "doc-2"]  # source identifiers only, never raw retrieved text

# 6. Tool Observability - tool calls, success/failure, parameter metadata (never values), latency, downstream errors
from agentic_ai.observability.tool_observability import trace_tool_call

with trace_tool_call(tracer, "search_jobs", argument_keys=["query", "location"], metrics=metrics):
    ...

# 7. Logs & Events - application/agent/tool/security/guardrail events, correlated by trace_id, persisted to Postgres
from agentic_ai.observability.events import EventLog, EventSeverity

events = EventLog("platform", postgres_url="postgresql://user:pass@localhost:5432/observability")
events.log_event("agent", "step_started", severity=EventSeverity.INFO, trace_id=get_current_trace_id())

# 8. Alerting & Incident Detection - real threshold evaluation + z-score anomaly detection
from agentic_ai.observability.alerting import AlertRule, detect_anomaly, evaluate_alerts

rules = [AlertRule(name="high-error-rate", metric_name="error_rate", threshold=0.05)]
evaluate_alerts(rules, {"error_rate": 0.08})  # -> [Alert(triggered=True, ...)]
detect_anomaly(current_latency, baseline_latencies)  # -> AnomalyResult(is_anomaly=True/False, z_score=...)

# 9. Correlation & Root Cause Analysis - every event for one trace_id, plus a direct link into Jaeger's own UI
from agentic_ai.observability.correlation import build_jaeger_trace_url, correlate

timeline = correlate(events, trace_id)  # the full cross-component timeline for one request, oldest first
build_jaeger_trace_url("http://localhost:16686", trace_id)  # -> a one-click link to the matching span timeline

# Bonus: provision a real Grafana dashboard reading straight from the Prometheus metrics above
from agentic_ai.observability.grafana import build_observability_dashboard, provision_dashboard

dashboard = build_observability_dashboard(datasource_uid="platform-prometheus")
provision_dashboard("http://localhost:3000", dashboard, username="admin", password="admin")

Monitoring & Alerting

The key difference from Observability: Observability collects the raw signal (logs, metrics, traces). Monitoring is the engine sitting on top of it - threshold + anomaly detection deciding when that signal crosses a line, turned into a routed, deduplicated, escalatable alert, and (via incident.py) a real incident in an on-call system. One submodule per capability - agentic_ai.monitoring.<domain> - covering the 7 core capabilities of this reference architecture: Health Monitoring, Performance Monitoring, AI/Agent Monitoring, Quality Monitoring, Cost Monitoring, Security/Guardrail Monitoring, and Alerting & Incident Management. rules.py's DEFAULT_AI_AGENT_ALERT_RULES are concrete, ready-to-use thresholds for an agentic AI system specifically.

# 1. Health Monitoring - availability across Agent/LLM/RAG/Tool/API/DB/infra, one uniform probe shape
from agentic_ai.monitoring.health import HealthMonitor, HealthStatus

health = HealthMonitor()
health.register("llm_gateway", lambda: True)  # a bool, or a HealthStatus directly
health.register("vector_db", lambda: HealthStatus.DEGRADED)
report = health.check_all()  # overall_status is the worst individual component - one UNHEALTHY dependency makes the whole report UNHEALTHY

# 2. Performance Monitoring - latency percentiles/error rate/throughput, pure Python, no Prometheus query needed
from agentic_ai.monitoring.performance import compute_performance_summary

summary = compute_performance_summary(latency_samples, total_requests=1000, failed_requests=12, window_seconds=60)
summary.latency.p95  # same P95 a Prometheus histogram_quantile() query would give you, computed in-process

# 3. AI/Agent Monitoring - task failure/loop/retry/tool-failure/model-error rates
from agentic_ai.monitoring.agent_monitoring import AgentMonitoringCounts, compute_agent_monitoring_snapshot

counts = AgentMonitoringCounts(total_tasks=1000, failed_tasks=80, total_steps=5000, loop_detections=120, total_tool_calls=1500, tool_failures=90)
snapshot = compute_agent_monitoring_snapshot(counts)  # -> task_failure_rate=0.08, loop_rate=0.024, tool_failure_rate=0.06, ...

# 4. Quality Monitoring - a rolling window of sampled quality scores, alerting on a drop, not a single bad score
from agentic_ai.monitoring.quality_monitoring import QualityMonitor

quality = QualityMonitor(window_size=200)
quality.record(judge_score, source="llm_judge_grounding")  # scoring itself is agentic_ai.evaluation.llm's job
quality.check_drift(baseline_mean=0.9, degradation_threshold_pct=10.0)  # -> is_degraded=True/False

# 5. Cost Monitoring - agentic_ai.governance.finops re-exported, plus the specific "cost/request up 50%" signal
from agentic_ai.monitoring.cost_monitoring import detect_cost_per_request_spike

detect_cost_per_request_spike(current_cost_per_request, baseline_cost_per_request)  # -> CostSpikeResult(is_spike=True/False, increase_pct=...)

# 6. Security & Guardrail Monitoring - policy violations, prompt injection, PII, unauthorized actions, as one rate
from agentic_ai.monitoring.security_monitoring import compute_security_monitoring_snapshot

compute_security_monitoring_snapshot(guardrail_audit_events)  # -> violation_rate, prompt_injection_count, pii_count, unauthorized_count

# 7. Alerting & Incident Management - dedup/route/escalate on top of threshold+anomaly detection, then a real PagerDuty incident
from agentic_ai.monitoring.alerting import AlertManager, evaluate_alerts
from agentic_ai.monitoring.rules import DEFAULT_AI_AGENT_ALERT_RULES
from agentic_ai.monitoring.incident import PagerDutyClient

manager = AlertManager()
manager.on("critical", lambda fired: PagerDutyClient(routing_key).trigger(fired.alert.rule.name, dedup_key=fired.dedup_key, severity="critical"))

alerts = evaluate_alerts(DEFAULT_AI_AGENT_ALERT_RULES, current_metric_values)
for alert in alerts:
    manager.fire(alert, scope="tenant-acme")  # repeats increment .count instead of re-notifying; a cleared condition auto-resolves

manager.escalate(timeout_seconds=300, handler=lambda fired: page_secondary_oncall(fired))  # unacknowledged alerts past the timeout

# Bonus: publish this module's own signals into the same Prometheus/Grafana stack Observability already exports to
from agentic_ai.monitoring.telemetry import MonitoringTelemetry
from agentic_ai.monitoring.grafana import build_monitoring_dashboard, provision_dashboard

telemetry = MonitoringTelemetry(metrics)  # metrics = the same agentic_ai.observability.metrics.MetricsRegistry instance
telemetry.set_health("llm_gateway", HealthStatus.HEALTHY)
telemetry.set_rate("agent_task_failure_rate", snapshot.task_failure_rate)

dashboard = build_monitoring_dashboard(datasource_uid="platform-prometheus")  # 9 panels, threshold lines matching DEFAULT_AI_AGENT_ALERT_RULES exactly
provision_dashboard("http://localhost:3000", dashboard, username="admin", password="admin")

Requirements

  • Python 3.10+
  • A LiteLLM proxy you deploy yourself (this library is a client, not a bundled server)
  • For Memory & State: nothing extra for in-memory/file/SQLite; Redis, Postgres (+pgvector), or Qdrant only if you choose those backends
  • For Secrets Management: a HashiCorp Vault instance you deploy yourself, and the [vault] extra
  • For Guardrails: nothing extra beyond the base install for deterministic detectors; the LLM-judged detectors need a gateway, same as Evaluation
  • For Authentication: a Keycloak instance you deploy yourself, and the [authentication] extra
  • For Identity: nothing extra - pure data models, no optional dependency at all
  • For Governance: an Open Policy Agent instance you deploy yourself; no new extra - built on the base httpx dependency
  • For Resilience & Reliability: nothing extra beyond the base install
  • For Observability: a Jaeger instance (OTLP/HTTP ingest) for tracing and the [tracing] extra; a Prometheus server to scrape metrics and the [metrics] extra (or [observability] for both); a Postgres database for Logs & Events; a Grafana instance with a Prometheus datasource already configured, for the optional dashboard provisioning
  • For Monitoring & Alerting: nothing extra for the core rate/threshold/ anomaly logic - built on the base install; the [observability] extra only if you use telemetry.py/grafana.py's live-dashboard path; a PagerDuty account (and one of its services' Events API v2 routing key) for Incident Integration

License

Apache-2.0

Metadata

Release files for enterprise-agentic-ai-framework 0.18.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for enterprise-agentic-ai-framework 0.18.0
File Size Uploaded Provenance Actions
enterprise_agentic_ai_framework-0.18.0.tar.gz 327.8 kB Without provenance Details for enterprise_agentic_ai_framework-0.18.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for enterprise-agentic-ai-framework 0.18.0
File Interpreter ABI Platform Actions
enterprise_agentic_ai_framework-0.18.0-py3-none-any.whl Python 3 none any Details for enterprise_agentic_ai_framework-0.18.0-py3-none-any.whl

Total release size: 663.7 kB

Release files / enterprise_agentic_ai_framework-0.18.0.tar.gz

Download URL enterprise_agentic_ai_framework-0.18.0.tar.gz
Size 327.8 kB
Tags Source
SHA-256 checksum
How to use checksums
c6347976a9a19a49cbab802373328ee7db15c6ad5a46f87d6145ecd989535481
BLAKE2b-256 checksum
How to use checksums
5670fade23724c6ff435d5519211517046665a9676bcab5d5459bdb9d2fd56b7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.8

Release files / enterprise_agentic_ai_framework-0.18.0-py3-none-any.whl

Download URL enterprise_agentic_ai_framework-0.18.0-py3-none-any.whl
Size 335.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
d1ef930fbd28f6095f5e36cd77ef8f3ed59dd4309d91087d07eb33c53c63403b
BLAKE2b-256 checksum
How to use checksums
6d0afbbeb218ab1f19c87ef221b8d8bae291f4cc309c2bcf744dafa9e09db675
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.8

Security for enterprise-agentic-ai-framework 0.18.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page