SDKs and frameworks
LangChain
Give your LangChain or LangGraph agent a native telem_search tool. Inside a LangGraph
graph, the tool attaches query lineage to every search.
Using a coding agent? Find the one you use on Integrations.
create_telem_search_tool(client) builds a native LangChain tool that uses a Telem
client. The model sets the query and, when the task needs it, a
date window. LangGraph injects its
ToolRuntime as a hidden second argument, and the tool reads the thread and the
messages from it.
Install
Section titled “Install”pip install "telem-sdk[langchain]"Authentication
Section titled “Authentication”Create an API key under API keys in the Telem console.
The guided installer writes it to ~/.telem/credentials.json, which the client
reads. You can also set it as TELEM_API_KEY, or pass it in code. See
API keys for the full rules.
Add the tool to a tool node in your graph, and give each conversation a thread_id
when you invoke the graph:
from langgraph.prebuilt import ToolNodefrom telem import Telemfrom telem.integrations.langchain import create_telem_search_tool
client = Telem() # environment, then ~/.telem/credentials.jsonsearch = create_telem_search_tool(client, num_results=5)
builder.add_node("tools", ToolNode([search])) # builder: your StateGraphgraph = builder.compile()
result = graph.invoke( {"messages": [...]}, config={"configurable": {"thread_id": chat_id}},)The tool answers with a ToolMessage. Its content is the text the model reads, and
its artifact is the typed SearchResponse. Search options such as tier,
providers_include, providers_exclude and num_results pass through to every
search() the tool makes. See Python SDK.
create_telem_search_tool() also takes goal, what the conversation is for, and
context, why the searches are made. Telem stores both with each search. The model
cannot change them for one search: the tool sends the same text every time.
The tool gives the model no way to read a page. Your own code can still read pages
with client.fetch(): see the Fetch tab on Python SDK.
The tool works the same with a sync Telem client (.invoke) or an async
AsyncTelem client (.ainvoke). Called directly, outside a graph
(search.invoke(...)), it sends only the query, with no lineage.
Subagents
Section titled “Subagents”To start a child graph as a subagent, build its config with
create_telem_child_config(), from the parent tool that starts it. The child’s
searches then appear in the console under the agent that started it:
from telem.integrations.langchain import create_telem_child_config
child_config = create_telem_child_config( parent_runtime, child_thread_id="child-1",)child_graph.invoke({"messages": [...]}, config=child_config)The config records the parent’s messages at that moment, and gives the child a new
thread_id that you choose. Call it when you start the child, not before. The record
is only as current as the parent’s state when you call it.
Conversation identity
Section titled “Conversation identity”configurable.thread_id is the conversation id: one thread is one conversation. A
child config from create_telem_child_config carries the child’s own. Without a
thread_id, the tool uses the first message’s id, and then the tool call id.
Never put thread state in a shared tool closure. ToolRuntime is injected for each
invocation. So one tool object is safe to reuse across concurrent threads. If you store
thread_id in a closure, one thread’s identity leaks into the requests of another
thread.
Next steps
Section titled “Next steps”- Python SDK: the client and every search option
- OpenAI: give an OpenAI client the same search tool
- Search parameters: choose providers, tiers and date windows