Skip to content

LangChain

create_telem_search_tool(client) builds a native LangChain tool backed by a Telem client. Only query is exposed to the model — LangGraph’s ToolRuntime is injected as a hidden second argument the model never sees, and it’s what carries thread and graph state into Telem when the tool runs inside a graph.

Terminal window
pip install "telem-sdk[langchain]"
  • Inside a LangGraph tool node (graph.invoke(...), a ToolNode, an agent loop), LangGraph injects ToolRuntime automatically. The tool then sends the active message branch plus flat trajectory-v5 metadata with every search, tagged HARNESS_ID = "langgraph".
  • Called directlytool.invoke(...) outside a graph — there is no runtime to inject, so the request stays history-free: just the query, no message history attached.

configurable.thread_id owns stable identity across calls in the same graph: it becomes the search’s conversation_id (unless create_telem_child_config has already set one explicitly); without either, identity falls back to the first message’s id, then the tool call id.

create_telem_child_config() freezes the parent runtime’s active branch — right now, at call time — and returns a LangGraph config for a child graph that appends the frozen parent snapshot to the child’s ancestor chain, plus a new thread_id you choose:

child_config = create_telem_child_config(
parent_runtime,
child_thread_id="child-1",
)
child_graph.invoke({"messages": [...]}, config=child_config)

Call it from the parent tool that starts the child graph, not before — the snapshot is only as current as the parent’s state at the moment you call it.

Never put thread state in a shared tool closure. ToolRuntime is injected per invocation precisely so one tool object is safe to reuse across concurrent threads; storing thread_id (or anything else thread-scoped) in a closure over the tool function will leak one thread’s identity into another’s requests.

The tool works the same with a sync Telem client (.invoke) or an async AsyncTelem client (.ainvoke). Called directly with no graph, it’s history-free:

from telem import Telem
from telem.integrations.langchain import create_telem_search_tool
with Telem() as client: # reads TELEM_API_KEY / TELEM_BASE_URL from the environment
search = create_telem_search_tool(client, num_results=2)
message = search.invoke({
"name": search.name,
"args": {"query": "what is the Telem search API"},
"id": "call-1",
"type": "tool_call",
})
print(message.content) # rendered text for the model
print(message.artifact) # typed SearchResponse

Inside a graph, pass config={"configurable": {"thread_id": ...}} and the tool node supplies ToolRuntime for you — see Python SDK for the underlying search() options every other keyword argument here forwards to.