feat(agents): Phase 10A — YouTube transcript subagent#17
Conversation
- Add youtube_agent_node: fetches transcript via youtube-transcript-api, oEmbed metadata via YouTube API (no key needed), runs hierarchical LLM summarization (chunk → parallel chunk summaries → final summary) - Add YOUTUBE_HANDOFF_TOOL_NAME + transfer_to_youtube_agent @tool in supervisor - Update supervisor system prompt with mandatory YouTube URL routing rules - Extend orchestrator _should_continue to route to youtube_agent node - Add youtube_context: str field to AxonState for cross-turn save flow - Add youtube_summary_model setting (default: google/gemini-2.5-flash) - Install youtube-transcript-api==0.6.3 + defusedxml==0.7.1 Flow: supervisor detects URL → transfer_to_youtube_agent tool call → youtube_agent_node fetches + summarizes → ToolMessage with JSON payload → supervisor presents title/channel/duration/summary/key_points + asks to save
|
Warning Rate limit exceeded
You’ve run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (6)
WalkthroughThis PR introduces a YouTube sub-agent to the multi-agent orchestrator, enabling the supervisor to delegate YouTube video URLs for transcript summarization. A new ChangesYouTube Sub-Agent & Routing
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
backend/app/agents/subagents/youtube_agent.py (1)
1-375: 🛠️ Refactor suggestion | 🟠 Major | 🏗️ Heavy liftSplit this sub-agent into smaller modules before it grows further.
At 375 lines, this file already exceeds the backend limit and mixes URL parsing, transcript I/O, chunking, prompting, model initialization, and node orchestration in one place. Please break the fetch/parse/summarize/schema pieces apart now; otherwise the Phase 10B/10C additions will make this much harder to change safely.
As per coding guidelines, "Always modular: one responsibility per file" and "No file longer than 300 lines — split into smaller modules."
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@backend/app/agents/subagents/youtube_agent.py` around lines 1 - 375, The file is doing multiple responsibilities; split it into smaller modules: 1) create a youtube_fetcher module containing _extract_video_id, _fetch_oembed, _fetch_transcript and the _YOUTUBE_URL_RE constant; 2) create a chunker module with _build_chunks, _CHARS_PER_TOKEN and _CHUNK_SIZE_CHARS; 3) create a summarizer module that holds _get_summary_model, _CHUNK_SUMMARY_SYSTEM, _CHUNK_SUMMARY_USER, _FINAL_SUMMARY_USER, _summarize_chunks, and _build_final_summary (including _MAX_CONCURRENT_SUMMARIES); and 4) keep orchestration in youtube_agent.py with youtube_agent_node, the tool constants, and the small helper _error_response only delegating to the new modules; update imports and adjust calls (e.g., import youtube_fetcher._extract_video_id, chunker._build_chunks, summarizer._summarize_chunks/_build_final_summary) and ensure logging and settings usage remain unchanged so behavior is preserved.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@backend/app/agents/subagents/youtube_agent.py`:
- Around line 218-219: The code currently parses the LLM JSON into a plain dict
and converts key_points with list(), which can turn a string into a char list
and allows arbitrary shape to be persisted to youtube_context; define a Pydantic
v2 model (e.g., YouTubeSummaryPayload with fields summary: str and key_points:
list[str]) near the helpers, then replace the raw json.loads + dict handling in
the function that reads content (the block returning str(data.get("summary",
"")), list(data.get("key_points", []))) to parse/validate via
YouTubeSummaryPayload.model_validate_json(content) (or model_validate after
json.loads) and return the validated summary and key_points; on validation
error, log/raise and avoid persisting corrupted payload. Apply the same change
to the other similar block referenced (lines ~346-355) so both LLM output and
persisted state use the same schema.
- Around line 132-139: The _fetch_transcript function currently offloads
synchronous YouTubeTranscriptApi.get_transcript using asyncio.to_thread which
will exhaust the threadpool under concurrency; replace this by either (A)
switching to an async transcript client that natively supports async calls, or
(B) implement a custom async wrapper that uses httpx.AsyncClient to perform the
same HTTP requests/parameter handling and parse the transcript responses
asynchronously (remove asyncio.to_thread and YouTubeTranscriptApi usage), and if
neither is possible add clear docstring/comments on _fetch_transcript (and where
it’s called) warning about the thread-pool trade-offs and limiting concurrency
(e.g., semaphore) to avoid exhausting the default executor.
In `@backend/app/agents/supervisor.py`:
- Around line 105-113: The supervisor's post-handoff prompt asks "Would you like
me to save this to your library?" even though the supervisor only binds the two
handoff tools and not save_video_transcript; update the supervisor logic (the
code around transfer_to_youtube_agent handling and the handoff tools binding in
supervisor) to either (A) only append the save prompt when save_video_transcript
is actually bound/available in the supervisor's tools set, or (B) bind the
save_video_transcript tool alongside the existing handoff tools so the
affirmative path can be executed; locate references to
transfer_to_youtube_agent, the supervisor tool-binding list, and any code that
formats the final YouTube result (also the similar block around the 164-166
region) and apply the conditional check or tool binding change accordingly.
In `@backend/pyproject.toml`:
- Line 25: The current call to YouTubeTranscriptApi.get_transcript(video_id) is
incompatible with youtube-transcript-api v1.2.0+; replace that call with the new
instance API: construct YouTubeTranscriptApi(), call .fetch(video_id) and then
.to_raw_data() to return the same transcript data (i.e., change
YouTubeTranscriptApi.get_transcript(video_id) to
YouTubeTranscriptApi().fetch(video_id).to_raw_data()). Also update any tests or
callers expecting the old return shape if needed, or alternatively change the
pyproject dependency to youtube-transcript-api<1.2.0 if you prefer to keep the
old static API.
In `@implementationPlan.MD`:
- Around line 261-264: The plan contains conflicting provider/model sources
(hardcoded gpt-4o-mini in youtube_agent vs settings.youtube_summary_model, and
TTS described both as OpenAI direct API and OpenRouter); unify these by choosing
a single configuration surface (e.g., settings.youtube_summary_model for
summarization and settings.tts_provider or settings.tts_api for TTS) and update
all references and descriptions to use those settings; ensure youtube_agent
reads from settings.youtube_summary_model (remove any gpt-4o-mini hardcode) and
the TTS section consistently documents the selected provider (OpenAI vs
OpenRouter) driven by settings.tts_provider so future implementers have one
source of truth.
- Around line 270-302: The markdown fenced-block containing the process flow
(starting with "User pastes YouTube URL" and steps like
"transfer_to_youtube_agent") lacks a language tag and the SQL fences (e.g., code
sections containing "INSERT into video_transcripts" and "INSERT into
audio_entries") are not separated by blank lines; update the flow block to
include a language (e.g., ```text or ```flow) and add a blank line before and
after each SQL fenced block so the SQL fences are isolated, then run
markdownlint to confirm no more fenced-block violations.
---
Outside diff comments:
In `@backend/app/agents/subagents/youtube_agent.py`:
- Around line 1-375: The file is doing multiple responsibilities; split it into
smaller modules: 1) create a youtube_fetcher module containing
_extract_video_id, _fetch_oembed, _fetch_transcript and the _YOUTUBE_URL_RE
constant; 2) create a chunker module with _build_chunks, _CHARS_PER_TOKEN and
_CHUNK_SIZE_CHARS; 3) create a summarizer module that holds _get_summary_model,
_CHUNK_SUMMARY_SYSTEM, _CHUNK_SUMMARY_USER, _FINAL_SUMMARY_USER,
_summarize_chunks, and _build_final_summary (including
_MAX_CONCURRENT_SUMMARIES); and 4) keep orchestration in youtube_agent.py with
youtube_agent_node, the tool constants, and the small helper _error_response
only delegating to the new modules; update imports and adjust calls (e.g.,
import youtube_fetcher._extract_video_id, chunker._build_chunks,
summarizer._summarize_chunks/_build_final_summary) and ensure logging and
settings usage remain unchanged so behavior is preserved.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 78a11cb7-164d-43a4-9305-9f6bac327c8e
⛔ Files ignored due to path filters (1)
backend/uv.lockis excluded by!**/*.lock,!**/uv.lock
📒 Files selected for processing (7)
backend/app/agents/orchestrator.pybackend/app/agents/state.pybackend/app/agents/subagents/youtube_agent.pybackend/app/agents/supervisor.pybackend/app/core/config.pybackend/pyproject.tomlimplementationPlan.MD
- Split youtube_agent.py (375 lines) into 3 focused modules: youtube_fetcher.py, youtube_chunker.py, youtube_summarizer.py (each under 170 lines; agent.py now ~140 lines — within 300-line rule) - Add Pydantic validation for LLM JSON output: YouTubeSummaryPayload validates final summary response (prevents string key_points being turned into a char list via list()) YouTubeVideoPayload validates full persisted payload before model_dump_json() - Update transcript API to youtube-transcript-api v1.x instance API: YouTubeTranscriptApi().fetch(video_id).to_raw_data() replaces deprecated static YouTubeTranscriptApi.get_transcript() - Add thread-pool usage docstring to fetch_transcript (asyncio.to_thread note) - Remove premature save CTA from supervisor system prompt: 'Would you like me to save this to your library?' removed since save_video_transcript tool is not yet bound (Phase 10B) - Fix implementationPlan.MD conflicting notes: gpt-4o-mini hardcode → settings.youtube_summary_model (Gemini 2.5 Flash) OpenAI direct TTS → OpenRouter openai/gpt-audio-mini Add language tag to flow fenced block; isolate SQL fences with blank lines
Flow: supervisor detects URL → transfer_to_youtube_agent tool call → youtube_agent_node fetches + summarizes → ToolMessage with JSON payload → supervisor presents title/channel/duration/summary/key_points + asks to save
Summary by CodeRabbit
New Features
Chores