semantic_search), by exact phrase (keyword_search), or both at once (hybrid ranking). This is THE way to retrieve relevant dialogue, segments, and clips: each result is one segment of one episode with bounded transcript windows pinpointing the highest-relevance lines, plus any highlight clips that overlap the segment, inline on the match.
This tool replaces the old
search_dialogue and list_clips tools. There is no separate clip-search tool — relevant clips arrive on these matches. A known episode’s full clip list is particle_podcast_get_episode with include: ["clips"].Segments vs clips
- Segments partition an episode’s transcript — where
start_line/end_lineare present, every spoken line belongs to exactly one segment and one segment’send_line + 1is the next one’sstart_line. They are contiguous in transcript lines, not in wall-clock seconds: the seconds between one segment’send_secondsand the next’sstart_secondscontain no transcribed speech. These matches do not carry the line ranges themselves — fetch them withparticle_podcast_get_episodeandinclude: ["segments"], where their absence marks an episode segmented by an earlier version, a small share of which do leave lines uncovered. Search ranks segments and returns the matching ones. - Clips are sparse, engagement-ranked highlights that overlap some segments. When a clip overlaps a ranked segment, it appears under an
Overlapping clips:line on that match.
particle_podcast_find_mentions instead — person_slug and company_slug here narrow ranked results, they don’t drive the ranking.
What semantic_search is not good at:
Crafting the query
semantic_search and keyword_search do different jobs. Most disappointing
results come from using one where the other belongs.
semantic_search carries the idea. Write it as a sentence describing what
should be discussed, in the words a speaker would actually use. It is
paraphrase-tolerant, so it finds the topic however it happens to be phrased.
keyword_search carries words that must be literally spoken. Every word
must appear in the same passage, so it is for one or two exact tokens — a
ticker, a product name, a drug name — not for a description. A sentence here
returns nothing, because no passage contains all of those words.
Use both when a topic must also contain an exact term. The result is their
intersection, which is narrow by design. If it comes back empty,
keyword_match: "ranked" relaxes the keyword side back to a relevance hint.
Start broad, then narrow
Every filter compounds, and each one can remove all results on its own. Issue the query withsemantic_search alone first, confirm the topic has coverage,
then add filters.
If a search returns nothing because of your filters, the tool returns an error
that names the specific parameter responsible and the corrected call to make —
it is measured by re-running your query with each filter removed, not guessed.
Act on it rather than re-issuing variations of the same query. When the query
text genuinely matches nothing, you get an ordinary empty result instead, which
is the signal to rephrase semantic_search.
role is the filter most likely to surprise: guest/host/panelist/
correspondent mean the person spoke in that specific capacity, speaker
means they spoke in any of them, and mention means they were talked about
rather than speaking. Omitting role covers speaking and mentions both, and is
almost always what you want. These are the same values /v1/podcasts/episodes
accepts.
Inputs
At least one ofsemantic_search or keyword_search is required.
Output
A markdown document with## Dialogue matches (N) and one ### Segment title section per match. Each section carries bulleted KV rows: - **Episode:**, - **Podcast:**, - **Podcast slug:**, - **Published:**, - **Episode slug:**, - **Segment type:**, - **Match:** (the source: semantic, keyword, or hybrid), then one or more bullets formatted Window @ start–end (or Preview @ … for truncated windows) followed by indented dialogue lines. Every line that matched the query is rendered with the entire Speaker: text wrapped in bold (a window can contain several matched lines); surrounding context renders as **Speaker:** text. When highlight clips overlap the segment, they appear under an Overlapping clips: line as bullets formatted Title (TYPE, score N) @ start–end — clip ID: <id>. When more pages exist, a horizontal rule and a **Cursor:** <value> line are appended.
Bolded lines mark the lines that ranked for the current query (a window can contain several). This is a different signal from the bolding in particle_podcast_find_mentions, where a bolded line means “this line names the resolved entity” — they answer different questions and can both be true within the same episode for different reasons.
Sample (semantic_search="how AI affects the labor market", limit=2):
- **Episode slug:** is what you can feed into particle_podcast_get_episode for the full transcript or clip list, or into particle_podcast_find_mentions (format=detail, episode_slug) for mention windows around a specific person.
Example
semantic_search and keyword_search:
Related
- REST equivalent:
GET /v1/podcasts/episodes/search. - For “every line naming X” use
particle_podcast_find_mentions. - For a known episode’s full clip list, use
particle_podcast_get_episodewithinclude: ["clips"]. - For metadata-only episode discovery (no dialogue), use
particle_podcast_list_episodes.