Skip to content

SDKs and frameworks

Wrap an OpenAI client, and the model gets a telem_search tool, with query lineage on every search. The wrap also records the conversation for you.

Using a coding agent? Find the one you use on Integrations.

Telem.wrap(client) patches an OpenAI client in place and returns the same object. Its chat.completions.create then has Telem search. For openai.AsyncOpenAI, use AsyncTelem.wrap(client). One wrapped client is one agent conversation.

Terminal window
pip install "telem-sdk[openai]"

openai is an optional extra. The wrap module is duck-typed. It imports the real package only to give a clearer error when the object you pass in is not shaped like an OpenAI client.

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.

from openai import OpenAI
from telem import Telem
telem = Telem() # environment, then ~/.telem/credentials.json
client = OpenAI() # reads OPENAI_API_KEY from the environment
telem.wrap(client) # patches client.chat.completions.create in place
completion = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "What's new in the Telem search API?"}],
)
print(completion.choices[0].message.content)
print(completion.telem_responses) # list[SearchResponse] telem ran answering this turn
print(client.telem_messages) # the recorded conversation so far

After each call, client.telem_messages holds every request and reply of the conversation.

The model gets one tool, telem_search. It sets the query and, when the task needs it, a date window. The wrap gives the model no tool to read a page. Your own code can still read pages with telem.fetch(): see the Fetch tab on Python SDK.

wrap() also takes options for every search the model makes:

Option What it sets
tier The search tier.
providers_include Only these providers.
num_results Results per provider. The server default is 5.
goal What the conversation is for, in a few words. Telem stores it with each search.
context Why the searches are made, in a sentence or two. Telem stores it with each search.
result_max_len The most characters of each result that the model reads. The default is 2,048.

An option you leave out falls back to the Telem client’s default, such as Telem(default_providers_exclude=[...]). See Python SDK. The model cannot change goal or context for one search: the wrap sends the same text with every search of the conversation.

The async version has the same shape. Use AsyncTelem and openai.AsyncOpenAI:

import asyncio
from openai import AsyncOpenAI
from telem import AsyncTelem
async def main():
telem = AsyncTelem()
client = AsyncOpenAI()
telem.wrap(client)
completion = await client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "What's new in the Telem search API?"}],
)
print(completion.choices[0].message.content)
asyncio.run(main())

Both examples need a real OPENAI_API_KEY, and both make a live model call.

Give a subagent its own wrapped client, and pass the parent’s client as parent. The subagent’s searches then appear in the console under the agent that started it:

child = OpenAI()
telem.wrap(child, parent=client) # when you delegate, not at startup

The wrap records the parent’s conversation at wrap() time. So wrap the child when you delegate to it. If you wrap it at startup, the record is older than anything the parent said.

One wrapped client is one conversation, and the wrap makes its own conversation id. If one conversation spans several wrapped clients, such as a web server that wraps a new client for each request, pass the same id each time:

telem.wrap(client, conversation_id=chat.id)

Without it, each request appears in the console as a separate conversation.

  • The context window starts at the first message. When you trim or summarize the history, a new window starts by itself. To name the window yourself, pass context_window_id.
  • After a search, client.telem_session_id holds the session id, for telem.sessions.

A stream=True call bypasses Telem completely. It gets no telem_search tool, no query lineage and no reply recording. The wrap emits a UserWarning each time this happens.

  • Python SDK: the client options, search options and errors
  • LangChain: the same search tool for LangChain and LangGraph agents
  • Search parameters: choose providers, tiers and date windows
Was this page helpful?