Integrations
Pyrula integrations adapt tools, models, and workflows across framework boundaries.
Everything imports from one place:
from pyrula.agents.integrations import ( from_langchain_tool, durable_chat_model, as_langgraph_node,)Two patterns
Section titled “Two patterns”Tool adapters wrap a single tool from another framework as a Pyrula
@tool. You pass the result to an @agent like any native
tool. from_langchain_tool works this way, and the wrapped call is journaled as a
durable step inside a run. durable_chat_model gives the same treatment to a LangChain
chat model’s own calls.
Durable nodes go the other direction: as_langgraph_node drops a durable Pyrula
workflow into a graph you already run, so one graph step is journaled, crash-safe, and
resumable, with human-in-the-loop bridged to the host’s own interrupt.
Durability depends on which side owns the journal. See What’s durable, and what isn’t before choosing an integration boundary.
Install
Section titled “Install”Each integration needs its framework installed. Some have a Pyrula extra:
| Integration | Install |
|---|---|
| LangChain tools | pip install pyrula-agents[langchain] |
| LangGraph | pip install pyrula-agents[langgraph] |
Custom integrations
Section titled “Custom integrations”Every durable integration is built on run_and_await: submit a workflow idempotently and
wait for its result. Use it to put a durable step inside a framework Pyrula doesn’t ship
an adapter for:
from pyrula.workflows import run_and_await
result = await run_and_await( store, "charge_order", {"order": "o-1"}, idempotency_key="charge:o-1", # becomes the run id; a retry re-attaches timeout=60,)It raises DurableInvocationError if the run fails, DurableInvocationTimeout past
timeout, and DurableInvocationCancelled if the run is cancelled. Pass
on_interrupt= to answer a ctx.interrupt from the caller’s side; without it the
interrupt surfaces as DurableInterrupt. A worker serving the workflow must be running.