Interop: connect foreign-framework agents
This is why Weave exists: take an agent someone already built (in LangChain, LangGraph, CrewAI, or plain Python) and connect it to your agent without rewriting it.
A foreign agent is wrapped into a Weave BaseAgent. Because it becomes an agent, it composes in Pipeline, Parallel, and any nesting exactly like a native one, and the connection protocol auto-calibrates the handoff (type-checks, injects transforms).
Duck-typed, zero new dependencies. These bridges call the foreign object's documented entrypoint (a LangChain Runnable's
ainvoke/invoke, a CrewAI crew'skickoff) rather than importing the framework. Weave's core stays dependency-free, and any object that speaks the interface plugs in, with no version pinning.
LangChain / LangGraph
from_langchain targets the Runnable protocol (ainvoke/invoke) that LangChain chains, chat models, agents, and compiled LangGraph graphs all implement.
from weave import from_langchain, Pipeline
# `chain` is any LangChain Runnable / LangGraph graph you already have.
theirs = from_langchain(chain, name="researcher")
# Connect it directly to your native Weave agent, no rewrite:
out = await Pipeline([theirs, my_agent]).run("a question")
The default extract pulls text out of common shapes: a str, a BaseMessage (.content), or an agent dict ({"output": ...}). Override it for custom shapes.
CrewAI
from_crewai targets kickoff / kickoff_async. CrewAI's kickoff(inputs=...) takes a dict, so map your Weave value into it with prepare.
from weave import from_crewai
theirs = from_crewai(my_crew, name="writers", prepare=lambda v: {"topic": v})
out = await theirs.run("electric cars")
The default extract returns a str or a CrewOutput.raw.
Anything else: from_callable
If a foreign agent isn't a LangChain/CrewAI object, wrap any sync or async value -> value function. This is the universal escape hatch:
from weave import from_callable
def persons_agent(text: str) -> str: # could call any SDK, HTTP API, etc.
return external_sdk.run(text)
theirs = from_callable(persons_agent, name="person_a")
Shaping the boundary
Every bridge accepts two optional callables:
| Hook | Signature | Purpose |
|---|---|---|
prepare | weave_value -> foreign_input | adapt the Weave value to what the foreign agent expects |
extract | foreign_output -> weave_value | pull a Weave-typed value back out |
Plus the standard port args: input, output (a DataType or PortSchema), name, and tags. Declare output=DataType.STRUCTURED_JSON when the foreign agent returns a dict you want to flow as structured data.
Extending to a new framework
Each framework is its own module under weave/interop/ that builds on the shared from_callable core. Adding one is a new file (its entrypoint name plus an extract default), never an edit to existing code (Open/Closed).