Skip to content

Adapters overview

Every framework adapter is a thin layer over GovernedToolbox. The adapter's job is to translate your framework's tool-registration convention into a register() call, and to convert the framework's tool-result protocol into the structured response Kite Logik returns on a denied call. Same policy engine, same audit log, same credential broker — just framework-shaped ergonomics.

Pick the adapter

FrameworkModuleUse when
OpenAI Chat Completionskitelogik.adapters.openaiPlain OpenAI() clients with tool calling
OpenAI Agents SDKkitelogik.adapters.openai_agentsMulti-agent orchestration, handoffs, agent-as-tool
LangChainkitelogik.adapters.langchainLCEL chains, LangChain Tool registrations
LangGraphkitelogik.adapters.langgraphStateGraph agents with ToolNode
CrewAIkitelogik.adapters.crewaiCrew-based multi-agent setups
Google ADKkitelogik.adapters.google_adkADK agents and tool registration
Pydantic AIkitelogik.adapters.pydantic_aiPydantic-typed agent definitions
LlamaIndexkitelogik.adapters.llamaindexLlamaIndex agents and FunctionTool
Semantic Kernelkitelogik.adapters.semantic_kernelSK plugin-based agents
Haystackkitelogik.adapters.haystackHaystack pipeline Tool dataclasses
Difykitelogik.adapters.difyDeployable Dify plugins via GovernedDifyTool

The four most-used adapters have full guides linked above. Pages for the other seven (CrewAI, Google ADK, Pydantic AI, LlamaIndex, Semantic Kernel, Haystack, Dify) are scheduled for the next docs round — until then, see the docstrings in kitelogik/adapters/ on GitHub.

All 11 ship in the base pip install kitelogik — no per-framework extras to install. See Installation → optional extras for the narrow set of extras (openai, google, dev).

The pattern is the same everywhere

Three steps for every adapter:

  1. Build a PolicyGate and a SessionContext
  2. Construct the framework's adapter, passing the gate and context
  3. register() your tool functions and let the framework call them
python
from kitelogik import OPAClient, PolicyGate, SessionContext

gate = PolicyGate(opa_client=OPAClient())
context = SessionContext(
    session_id="s1",
    user_role="support_agent",
    session_scopes=["read_customer", "approve_refund"],
)

Then for whichever framework:

OpenAI

python
from kitelogik.adapters.openai import OpenAIAdapter

adapter = OpenAIAdapter(gate=gate, context=context)
adapter.register("approve_refund", approve_refund_fn, schema=schema)

tools   = adapter.openai_tool_schemas()      # pass to OpenAI API
results = await adapter.execute_all(calls)   # governed execution

LangChain

python
from kitelogik.adapters.langchain import govern_toolkit

tools = govern_toolkit(existing_tools, gate=gate, context=context)
agent = create_react_agent(llm, tools=tools)

The govern_toolkit helper wraps an existing list of LangChain Tool objects in one call. There's also a per-tool as_governed_tool for finer-grained control.

How denied calls surface to the framework

@governed raises GovernanceError for the caller to handle. Adapters do something different: they convert a denial into a structured [BLOCKED] string returned as the tool result, so the agent loop sees "the tool ran and returned a refusal" rather than an unhandled exception. This keeps the loop alive and lets the model decide what to do next (retry with different args, escalate to user, give up).

You can opt out of this behaviour per-adapter — see the per-adapter pages linked above, or the docstrings in kitelogik/adapters/ on GitHub.

What's the same across all adapters

  • Same GovernanceEvent shape on every tool call
  • Same PolicyDecision returned by the gate
  • Same AuditStore write per decision (when enabled)
  • Same HITLQueue for requires_hitl := true decisions
  • Same CredentialBroker for session-scoped tokens
  • Same OpenTelemetry spans on every evaluation

So switching from one framework to another is a one-line import change on the adapter side; the policies and the audit pipeline don't move.

Per-adapter guides

Released under the Apache 2.0 License.