Framework Adapters

Adapters map a framework-specific agent to an EntroPy-instrumentable callable returning an AgentRun. They import their target framework lazily, so import entropy works even when none are installed.

Every adapter exposes a from_* helper and is also reachable through automatic routing with find_adapter:

from entropy import (from_langchain, from_langgraph, from_openai,
                     from_crewai, from_pydanticai, from_autogen,
                     from_google_adk, from_mcp, from_custom, find_adapter)

runnable = from_langchain(my_langchain_agent)   # now a callable -> AgentRun
runnable = find_adapter(my_langchain_agent)()   # auto-detect the framework
HelperFrameworkExtra
from_langchainLangChainlangchain
from_langgraphLangGraphlanggraph
from_openaiOpenAI Agentsopenai
from_crewaiCrewAIcrewai
from_pydanticaiPydanticAIpydanticai
from_autogenAutoGenautogen
from_google_adkGoogle ADKgoogle-adk
from_mcpMCPmcp
from_customYour own wrapper

Code per framework

Each snippet below builds a minimal agent, wraps it with the matching adapter, and runs a Monte Carlo evaluation. Wrap the call in a small retry helper if your model is flaky (local GPU models sometimes 500).

LangChain

from langchain_core.runnables import RunnableLambda
from entropy import from_langchain, Suite, Dataset, Case

agent = RunnableLambda(lambda x: {"output": x["input"] + "!"})
wrapped = from_langchain(agent)

results = Suite(seed=42).run(
    wrapped, Dataset([Case(input="hi", expected="hi!")]), trials=100,
)
print(results["success_rate"], results["behavioral_entropy"])

LangGraph / create_agent

from langchain.agents import create_agent
from langchain_core.tools import tool
from langchain_ollama import ChatOllama
from entropy import from_langgraph, Suite, Dataset, Case

@tool
def get_weather(city: str) -> str:
    """Return a canned weather report for a city."""
    return f"It is sunny in {city}."

agent = create_agent(ChatOllama(model="minimax-m3:cloud", temperature=0.0),
                     tools=[get_weather],
                     system_prompt="You are a helpful assistant. Answer concisely.")
wrapped = from_langgraph(agent)   # create_agent -> CompiledStateGraph

results = Suite(seed=42).run(
    wrapped,
    Dataset([Case(input="weather in Paris?",
                  check=lambda o: "sunny" in (o or "").lower())]),
    trials=10,
)

create_agent returns a CompiledStateGraph whose result is {"messages": [...]} (no "output" key) and expects {"messages": [HumanMessage(...)]} as input. The adapter handles both shapes automatically.

OpenAI Agents SDK

from agents import Agent
from entropy import from_openai, Suite, Dataset, Case

agent = Agent(name="assistant", instructions="You are helpful.")
wrapped = from_openai(agent)

results = Suite(seed=42).run(
    wrapped, Dataset([Case(input="hi", expected="hi")]), trials=10,
)

CrewAI

from crewai import Agent, Task, Crew
from entropy import from_crewai, Suite, Dataset, Case

researcher = Agent(role="researcher", goal="answer questions", backstory="expert")
task = Task(description="Answer the user: {input}", agent=researcher)
crew = Crew(agents=[researcher], tasks=[task])
wrapped = from_crewai(crew)

results = Suite(seed=42).run(
    wrapped, Dataset([Case(input="What is 2+2?")]), trials=10,
)

PydanticAI

from pydantic_ai import Agent
from entropy import from_pydanticai, Suite, Dataset, Case

agent = Agent("openai:gpt-4o", instructions="Be helpful.")
wrapped = from_pydanticai(agent)

results = Suite(seed=42).run(
    wrapped, Dataset([Case(input="hi")]), trials=10,
)

AutoGen

from autogen import ConversableAgent
from entropy import from_autogen, Suite, Dataset, Case

agent = ConversableAgent("bot", llm_config={"config_list": [...]})
wrapped = from_autogen(agent)

results = Suite(seed=42).run(
    wrapped, Dataset([Case(input="hi")]), trials=10,
)

Google ADK

from google.adk.agents import LlmAgent
from entropy import from_google_adk, Suite, Dataset, Case

agent = LlmAgent(model="gemini-2.0-flash", name="assistant",
                 instruction="Be helpful.")
wrapped = from_google_adk(agent)

results = Suite(seed=42).run(
    wrapped, Dataset([Case(input="hi")]), trials=10,
)

MCP

from mcp import ClientSession
from entropy import from_mcp, Suite, Dataset, Case

# `session` is an already-connected MCP ClientSession
wrapped = from_mcp(session, tool="run")

results = Suite(seed=42).run(
    wrapped, Dataset([Case(input="hi")]), trials=10,
)

Your own agent (custom)

from entropy import from_custom, Suite, Dataset, Case

def my_agent(inp):
    return "echo: " + inp

wrapped = from_custom(my_agent)

results = Suite(seed=42).run(
    wrapped, Dataset([Case(input="hi", expected="echo: hi")]), trials=100,
)

Discovery & custom adapters

List registered adapters, or build your own with the @adapter decorator (see Plugins):

from entropy import list_adapters, find_adapter, adapter, Adapter

print(list_adapters())

@adapter("myfw")
class MyAdapter(Adapter):
    def match(self, agent): return hasattr(agent, "run_myfw")
    def wrap(self, agent):
        def call(inp):
            res = agent.run_myfw(inp)
            from entropy import AgentRun
            return AgentRun(run_id="", input=inp, output=res)
        return call