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.
Install
Section titled “Install”pip install "telem-sdk[langchain]"Graph calls vs. direct calls
Section titled “Graph calls vs. direct calls”- Inside a LangGraph tool node (
graph.invoke(...), aToolNode, an agent loop), LangGraph injectsToolRuntimeautomatically. The tool then sends the active message branch plus flat trajectory-v5 metadata with every search, taggedHARNESS_ID = "langgraph". - Called directly —
tool.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.
Subagent lineage
Section titled “Subagent lineage”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 Telemfrom 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 modelprint(message.artifact) # typed SearchResponseInside 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.