Skip to content
Changelog

Fixes for YouTubeTools, PerplexitySearch, PubmedTools and InMemoryDb

October 19, 20261 min read

Agno fixes YouTubeTools, PerplexitySearch, PubmedTools and InMemoryDb in this release. Each block below shows real output from the previous release and this one, with mocks in place of the YouTube, Perplexity and PubMed HTTP calls.

get_youtube_video_id accepted only youtube.com, www.youtube.com and youtu.be, and on YouTube only the /watch, /embed/ and /v/ paths. A Shorts link pasted into a chat came back as No video ID found. The parser now adds /shorts/ and /live/, the mobile, music and privacy-enhanced hosts, the youtube.com.br and youtube.co.uk hosts, and links typed without a scheme:

URL                                                  Before   Now
https://www.youtube.com/shorts/BGQWPY4IigY           None     'BGQWPY4IigY'
https://www.youtube.com/live/BGQWPY4IigY             None     'BGQWPY4IigY'
https://m.youtube.com/watch?v=BGQWPY4IigY            None     'BGQWPY4IigY'
https://music.youtube.com/watch?v=BGQWPY4IigY        None     'BGQWPY4IigY'
https://www.youtube-nocookie.com/embed/BGQWPY4IigY   None     'BGQWPY4IigY'
youtu.be/BGQWPY4IigY                                 None     'BGQWPY4IigY'

A link with an empty id, such as https://youtu.be/, used to yield an empty string. get_youtube_video_captions passed it to the transcript API and get_youtube_video_data asked oEmbed about watch?v=. All three tools now stop at No video ID found:

get_youtube_video_data("https://youtu.be/")
Before: requests https://www.youtube.com/oembed?format=json&url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3D
Now:    'No video ID found', no request
 
get_youtube_video_captions("https://youtu.be/")
Before: YouTubeTranscriptApi().fetch('')
Now:    'No video ID found', no request

PerplexitySearch and PubmedTools keep max_results=0

PerplexitySearch.search, PerplexitySearch.asearch and PubmedTools.search_pubmed read max_results or self.max_results. Python treats 0 as false, so an explicit 0 quietly became the toolkit default. They now fall back only when max_results is None:

Call                                                          Before      Now
PerplexitySearch(max_results=5).search(q, max_results=0)      sends 5     sends 0
PerplexitySearch(max_results=5).asearch(q, max_results=0)     sends 5     sends 0
PubmedTools(max_results=3).search_pubmed(q, max_results=0)    retmax=3    retmax=0

InMemoryDb keeps its own copy of a memory

InMemoryDb.upsert_user_memory stored the dict from UserMemory.to_dict(), which shares the caller's topics list. Editing the UserMemory after the upsert rewrote the stored memory and every topic listing, with no second write. The upsert now stores a deep copy on both the insert and the update path, and upsert_memories inherits it:

db = InMemoryDb()
memory = UserMemory(memory_id="m1", user_id="alice", memory="Alice ships agents on Fridays", topics=["agents"])
db.upsert_user_memory(memory)
memory.topics.append("unsaved")
 
db.get_all_memory_topics(user_id="alice")
# Before: ['agents', 'unsaved']
# Now:    ['agents']

See the cookbook, and learn more about YouTubeTools, Perplexity, PubMed and in-memory storage in the documentation.

Frequently asked questions

Earlier releases of YouTubeTools recognised only youtube.com, www.youtube.com and youtu.be, and only the /watch, /embed/ and /v/ paths. It now also reads /shorts/ and /live/ paths, the m., music. and youtube-nocookie.com hosts, and links pasted without https://.

A link such as https://youtu.be/ makes get_youtube_video_captions, get_youtube_video_data and get_video_timestamps return No video ID found without calling YouTube. Earlier releases sent the empty id on to the transcript API or the oEmbed endpoint.

Yes. Both now send 0 as given. A missing max_results still falls back to the toolkit setting, which is 5 for PerplexitySearch and 10 for PubmedTools when you set none.

InMemoryDb.upsert_user_memory used to keep a reference to the topics list of the UserMemory you passed in, so appending to it later changed the stored memory. It now stores a deep copy, and upsert_memories gets the same copy for every memory.

Shipped around the same time