Uh oh!
There was an error while loading. Please reload this page.
feat(agents): migrate remaining one-shot LLM calls to Pydantic AI agents (#147) - #296
Conversation
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📥 CommitsReviewing files that changed from the base of the PR and between 1b816cecd1924d4c086d307a58ca5275e00d11c7 and 09ce721. 📒 Files selected for processing (12)
✅ Files skipped from review due to trivial changes (1)
🚧 Files skipped from review as they are similar to previous changes (10)
📝 WalkthroughWalkthroughThis PR migrates three remaining one-shot Gemini call sites to typed Pydantic AI agents, adds a shared sync bridge, updates provider defaults, and rewires the affected routes, health check, tests, and spec. ChangesAgent migration
Estimated code review effort: 3 (Moderate) | ~30 minutes Sequence Diagram(s)sequenceDiagram
participant Client
participant Route as sync route handler
participant run_agent_sync
participant Agent as Pydantic AI agent
participant Supabase
Client->>Route: HTTP request
Route->>Route: build deps / prompt
Route->>run_agent_sync: run_agent_sync(agent.run(...))
run_agent_sync->>Agent: run(input)
alt success
Agent-->>run_agent_sync: typed output
run_agent_sync-->>Route: result
Route->>Supabase: persist or load cached data
Route-->>Client: 200 response
else failure
Agent-->>run_agent_sync: exception
Route-->>Client: 502 or fallback response
end
Possibly related issues
Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 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 |
Deploying with |
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs | frontend-staging | 09ce721 | Commit Preview URL Branch Preview URL | Jul 01 2026, 02:27 PM |
1b816ce to
5f0badeCompareThere was a problem hiding this comment.
🧹 Nitpick comments (2)
backend/agents/social_summary.py (1)
35-35: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueDuplicate prompt-hash boilerplate across agents.
The
hashlib.sha256(...).hexdigest()[:12]pattern for_PROMPT_HASHis repeated verbatim inbackend/agents/study_guide.py. As more agents are added under this pattern, consider extracting a small shared helper (e.g.agents/_providers.py::prompt_version(prompt: str) -> str) to avoid re-implementing this in every new agent module.♻️ Suggested helper
+# agents/_providers.py+def prompt_version(system_prompt: str) -> str:+ import hashlib+ return hashlib.sha256(system_prompt.encode("utf-8")).hexdigest()[:12]-import hashlib- from pydantic import BaseModel, Field from pydantic_ai import Agent -from agents._providers import model_for+from agents._providers import model_for, prompt_version from agents.deps import SaplingDeps ... -_PROMPT_HASH = hashlib.sha256(_SYSTEM_PROMPT.encode("utf-8")).hexdigest()[:12]+_PROMPT_HASH = prompt_version(_SYSTEM_PROMPT)Also applies to: 38-44
🤖 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/agents/social_summary.py` at line 35, Duplicate prompt-hash boilerplate is repeated in social_summary and study_guide; extract the shared SHA-256 truncation logic into a small helper such as agents/_providers.py::prompt_version(prompt: str) -> str, then update _PROMPT_HASH in each agent module to call it instead of re-implementing hashlib.sha256(...).hexdigest()[:12].backend/agents/study_guide.py (1)
43-62: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueLGTM! Typed output correctly mirrors the legacy JSON contract, matching
result.output.model_dump()usage inroutes/study_guide.py. Same prompt-hash duplication note as inagents/social_summary.pyapplies here (see that comment) — extracting a shared helper would avoid re-implementing this in future agents.🤖 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/agents/study_guide.py` around lines 43 - 62, The prompt hash logic is duplicated in study_guide agent setup and should be centralized to match the shared pattern used by other agents. Extract the SHA-256 prompt-version calculation into a reusable helper and have study_guide_agent build its metadata from that helper instead of re-implementing the hash inline. Keep the existing _SYSTEM_PROMPT, _PROMPT_HASH, and study_guide_agent symbols as the integration points when refactoring.
🤖 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.
Nitpick comments:
In `@backend/agents/social_summary.py`:
- Line 35: Duplicate prompt-hash boilerplate is repeated in social_summary and
study_guide; extract the shared SHA-256 truncation logic into a small helper
such as agents/_providers.py::prompt_version(prompt: str) -> str, then update
_PROMPT_HASH in each agent module to call it instead of re-implementing
hashlib.sha256(...).hexdigest()[:12].
In `@backend/agents/study_guide.py`:
- Around line 43-62: The prompt hash logic is duplicated in study_guide agent
setup and should be centralized to match the shared pattern used by other
agents. Extract the SHA-256 prompt-version calculation into a reusable helper
and have study_guide_agent build its metadata from that helper instead of
re-implementing the hash inline. Keep the existing _SYSTEM_PROMPT, _PROMPT_HASH,
and study_guide_agent symbols as the integration points when refactoring.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: e33a7124-0193-4aba-988a-15fecc891aae
📥 Commits
Reviewing files that changed from the base of the PR and between d86edde and 1b816cecd1924d4c086d307a58ca5275e00d11c7.
📒 Files selected for processing (12)
backend/agents/_providers.pybackend/agents/_run.pybackend/agents/health.pybackend/agents/social_summary.pybackend/agents/study_guide.pybackend/main.pybackend/routes/social.pybackend/routes/study_guide.pybackend/tests/test_gemini_test_auth.pybackend/tests/test_oneshot_agents.pybackend/tests/test_study_guide_routes.pyspecs/147-oneshot-llm-agents.md
Closes#147 (part of the Agent-migration epic #152, milestone "Agent migration surfaces + staging + performance").
What
Retires the last three direct
call_gemini*production call sites onto typed Pydantic AI agents. After this, the only backendgemini_servicecallers are the intentional legacy chat fallback (routes/learn.py, retired in the #151 cutover) and tests.routes/study_guide.pycall_gemini_json(prompt)agents/study_guide.py(study_guide_agent)routes/social.pycall_gemini(...)agents/social_summary.py(social_summary_agent)main.py/api/gemini-testcall_gemini(...)agents/health.py(health_probe_agent)Notes
StudyGuide/Topicmirror the existingexam/due_date/overview/topicsJSON; the routemodel_dump()s straight intostudy_guides.content, so cached reads and the frontend are unaffected./overviewand/api/gemini-testresponse shapes are identical.get_cached_summary → run → save_summaryflow and the graceful fallback string (still 200) on agent failure.GoogleProviderfromagents/_providers.py, so a green check means the real agent seam reaches Gemini. Admin-before-spend gate preserved.agents/_run.py::run_agent_syncwrapsasyncio.runfor the three sync handlers (their surrounding httpxtable()access stays synchronous). Handlers are not converted toasync def._providers.pyregistersstudy_guide(gemini-2.5-flash) andsocial_summary(gemini-2.5-flash-lite), both env-overridable viaSAPLING_MODEL_*.Testing
test_study_guide_routes.pyandtest_gemini_test_auth.pyto mock the agents; addedtest_oneshot_agents.pycovering the 502 path, social cache-hit/miss/agent-failure, and theStudyGuide → legacy-dictshape.test_storage_servicefailures are pre-existing onmain— missing SUPABASE env — verified by stash-and-run).ruff checkclean on all changed files.Out of scope (separate issues): quiz, documents, calendar, flashcards,
course_context_service, thelearn.pylegacy fallback, and deletinggemini_service.py(#151).🤖 Generated with Claude Code
Summary by CodeRabbit
{ok, reply}/{ok, error}).502error when generation cannot be completed.