feat(agents): migrate remaining one-shot LLM calls to Pydantic AI agents (#147) - #296

Merged
Jose-Gael-Cruz-Lopez merged 201 commits into
mainfrom
feat/147-oneshot-llm-agents
Jul 1, 2026
Merged

feat(agents): migrate remaining one-shot LLM calls to Pydantic AI agents (#147)#296
Jose-Gael-Cruz-Lopez merged 201 commits into
mainfrom
feat/147-oneshot-llm-agents

Conversation

@Jose-Gael-Cruz-Lopez

@Jose-Gael-Cruz-LopezJose-Gael-Cruz-Lopez commented Jul 1, 2026

Copy link
Copy Markdown
Member

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 backend gemini_service callers are the intentional legacy chat fallback (routes/learn.py, retired in the #151 cutover) and tests.

SurfaceBeforeAfter
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

  • Contracts unchanged.StudyGuide/Topic mirror the existing exam/due_date/overview/topics JSON; the route model_dump()s straight into study_guides.content, so cached reads and the frontend are unaffected. /overview and /api/gemini-test response shapes are identical.
  • Study-guide failures now return 502 (per the issue's audit note) instead of a raw 500.
  • Social summary keeps the get_cached_summary → run → save_summary flow and the graceful fallback string (still 200) on agent failure.
  • Health probe runs through the shared GoogleProvider from agents/_providers.py, so a green check means the real agent seam reaches Gemini. Admin-before-spend gate preserved.
  • Sync→async bridge:agents/_run.py::run_agent_sync wraps asyncio.run for the three sync handlers (their surrounding httpx table() access stays synchronous). Handlers are not converted to async def.
  • _providers.py registers study_guide (gemini-2.5-flash) and social_summary (gemini-2.5-flash-lite), both env-overridable via SAPLING_MODEL_*.

Testing

  • Updated test_study_guide_routes.py and test_gemini_test_auth.py to mock the agents; added test_oneshot_agents.py covering the 502 path, social cache-hit/miss/agent-failure, and the StudyGuide → legacy-dict shape.
  • Full backend suite: 829 passed (the 2 test_storage_service failures are pre-existing on main — missing SUPABASE env — verified by stash-and-run).
  • ruff check clean on all changed files.

Out of scope (separate issues): quiz, documents, calendar, flashcards, course_context_service, the learn.py legacy fallback, and deleting gemini_service.py (#151).

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added AI-generated study guides and social room overview summaries using structured, typed outputs.
    • Updated the admin Gemini health check to run through the app’s agent-based flow (preserving {ok, reply} / {ok, error}).
  • Bug Fixes
    • Improved resilience: cache-first behavior remains, and summary generation still falls back to the legacy contract when AI fails.
    • Study guide generation now returns a clearer 502 error when generation cannot be completed.
  • Tests
    • Expanded and updated tests for agent execution, caching behavior, failure handling, and typed output shape serialization.

@coderabbitai

coderabbitaiBot commented Jul 1, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 36b5c5f0-1c9e-4623-ba33-a9861a267129

📥 Commits

Reviewing files that changed from the base of the PR and between 1b816cecd1924d4c086d307a58ca5275e00d11c7 and 09ce721.

📒 Files selected for processing (12)
  • backend/agents/_providers.py
  • backend/agents/_run.py
  • backend/agents/health.py
  • backend/agents/social_summary.py
  • backend/agents/study_guide.py
  • backend/main.py
  • backend/routes/social.py
  • backend/routes/study_guide.py
  • backend/tests/test_gemini_test_auth.py
  • backend/tests/test_oneshot_agents.py
  • backend/tests/test_study_guide_routes.py
  • specs/147-oneshot-llm-agents.md
✅ Files skipped from review due to trivial changes (1)
  • specs/147-oneshot-llm-agents.md
🚧 Files skipped from review as they are similar to previous changes (10)
  • backend/agents/_run.py
  • backend/agents/health.py
  • backend/agents/study_guide.py
  • backend/routes/study_guide.py
  • backend/tests/test_study_guide_routes.py
  • backend/routes/social.py
  • backend/main.py
  • backend/tests/test_oneshot_agents.py
  • backend/agents/social_summary.py
  • backend/agents/_providers.py

📝 Walkthrough

Walkthrough

This 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.

Changes

Agent migration

Layer / File(s)Summary
Task defaults and sync bridge
backend/agents/_providers.py, backend/agents/_run.py
Adds study_guide and social_summary to AgentTask and _DEFAULTS, and introduces run_agent_sync for running agent coroutines from sync handlers.
Health probe agent and gemini-test endpoint
backend/agents/health.py, backend/main.py, backend/tests/test_gemini_test_auth.py
Adds health_probe_agent, rewires /api/gemini-test to run it via run_agent_sync, and updates auth/success/failure tests.
Social summary agent and room overview route
backend/agents/social_summary.py, backend/routes/social.py, backend/tests/test_oneshot_agents.py
Adds SocialSummary and social_summary_agent, switches the overview cache-miss path to agent execution, and adds cache-hit/miss/error coverage.
Study guide agent and generation route
backend/agents/study_guide.py, backend/routes/study_guide.py, backend/tests/test_study_guide_routes.py, backend/tests/test_oneshot_agents.py
Adds Topic/StudyGuide and study_guide_agent, rewires generation to agent execution with 502 failure handling, and updates route/output-shape tests.
Migration spec document
specs/147-oneshot-llm-agents.md
Documents the migration requirements and acceptance criteria.

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
Loading

Possibly related issues

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 23.81% which is insufficient. The required threshold is 80.00%.Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check nameStatusExplanation
Title check✅ PassedThe title clearly summarizes the main change: migrating remaining one-shot LLM calls to Pydantic AI agents.
Description check✅ PassedThe description covers the goal, key changes, testing, and related issue, though it doesn't strictly follow the template headings.
Linked Issues check✅ PassedThe three targeted call sites were migrated off direct call_gemini* usage, error handling matches the issue, and remaining callers are legacy fallback and tests.
Out of Scope Changes check✅ PassedThe added modules, bridge helper, tests, and spec document all support the stated migration and do not appear unrelated.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/147-oneshot-llm-agents

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@cloudflare-workers-and-pages

cloudflare-workers-and-pagesBot commented Jul 1, 2026

Copy link
Copy Markdown

Deploying with Cloudflare Workers Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

StatusNameLatest CommitPreview URLUpdated (UTC)
✅ Deployment successful!
View logs
frontend-staging09ce721Commit Preview URL

Branch Preview URL
Jul 01 2026, 02:27 PM

@Jose-Gael-Cruz-Lopez
Jose-Gael-Cruz-Lopezforce-pushed the feat/147-oneshot-llm-agents branch from 1b816ce to 5f0badeCompareJuly 1, 2026 08:38

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
backend/agents/social_summary.py (1)

35-35: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Duplicate prompt-hash boilerplate across agents.

The hashlib.sha256(...).hexdigest()[:12] pattern for _PROMPT_HASH is repeated verbatim in backend/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 value

LGTM! Typed output correctly mirrors the legacy JSON contract, matching result.output.model_dump() usage in routes/study_guide.py. Same prompt-hash duplication note as in agents/social_summary.py applies 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.py
  • backend/agents/_run.py
  • backend/agents/health.py
  • backend/agents/social_summary.py
  • backend/agents/study_guide.py
  • backend/main.py
  • backend/routes/social.py
  • backend/routes/study_guide.py
  • backend/tests/test_gemini_test_auth.py
  • backend/tests/test_oneshot_agents.py
  • backend/tests/test_study_guide_routes.py
  • specs/147-oneshot-llm-agents.md

#147)
Closes an acceptance-#5 gap found in review: the probe-failure branch in
gemini_test (except → {ok:false,error}, still 200) was untested. Adds a case
that raises from health_probe_agent.run and asserts the failure contract.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[P2] Agent migration: remaining one-shot LLM calls (study guide, social, health) → agents/seam

1 participant

@Jose-Gael-Cruz-Lopez
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

feat(agents): migrate remaining one-shot LLM calls to Pydantic AI agents (#147) - #296

Merged
Jose-Gael-Cruz-Lopez merged 201 commits into
mainfrom
feat/147-oneshot-llm-agents
Jul 1, 2026
Merged

feat(agents): migrate remaining one-shot LLM calls to Pydantic AI agents (#147)#296
Jose-Gael-Cruz-Lopez merged 201 commits into
mainfrom
feat/147-oneshot-llm-agents

Conversation

@Jose-Gael-Cruz-Lopez

@Jose-Gael-Cruz-LopezJose-Gael-Cruz-Lopez commented Jul 1, 2026

Copy link
Copy Markdown
Member

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 backend gemini_service callers are the intentional legacy chat fallback (routes/learn.py, retired in the #151 cutover) and tests.

SurfaceBeforeAfter
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

  • Contracts unchanged.StudyGuide/Topic mirror the existing exam/due_date/overview/topics JSON; the route model_dump()s straight into study_guides.content, so cached reads and the frontend are unaffected. /overview and /api/gemini-test response shapes are identical.
  • Study-guide failures now return 502 (per the issue's audit note) instead of a raw 500.
  • Social summary keeps the get_cached_summary → run → save_summary flow and the graceful fallback string (still 200) on agent failure.
  • Health probe runs through the shared GoogleProvider from agents/_providers.py, so a green check means the real agent seam reaches Gemini. Admin-before-spend gate preserved.
  • Sync→async bridge:agents/_run.py::run_agent_sync wraps asyncio.run for the three sync handlers (their surrounding httpx table() access stays synchronous). Handlers are not converted to async def.
  • _providers.py registers study_guide (gemini-2.5-flash) and social_summary (gemini-2.5-flash-lite), both env-overridable via SAPLING_MODEL_*.

Testing

  • Updated test_study_guide_routes.py and test_gemini_test_auth.py to mock the agents; added test_oneshot_agents.py covering the 502 path, social cache-hit/miss/agent-failure, and the StudyGuide → legacy-dict shape.
  • Full backend suite: 829 passed (the 2 test_storage_service failures are pre-existing on main — missing SUPABASE env — verified by stash-and-run).
  • ruff check clean on all changed files.

Out of scope (separate issues): quiz, documents, calendar, flashcards, course_context_service, the learn.py legacy fallback, and deleting gemini_service.py (#151).

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added AI-generated study guides and social room overview summaries using structured, typed outputs.
    • Updated the admin Gemini health check to run through the app’s agent-based flow (preserving {ok, reply} / {ok, error}).
  • Bug Fixes
    • Improved resilience: cache-first behavior remains, and summary generation still falls back to the legacy contract when AI fails.
    • Study guide generation now returns a clearer 502 error when generation cannot be completed.
  • Tests
    • Expanded and updated tests for agent execution, caching behavior, failure handling, and typed output shape serialization.

@coderabbitai

coderabbitaiBot commented Jul 1, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 36b5c5f0-1c9e-4623-ba33-a9861a267129

📥 Commits

Reviewing files that changed from the base of the PR and between 1b816cecd1924d4c086d307a58ca5275e00d11c7 and 09ce721.

📒 Files selected for processing (12)
  • backend/agents/_providers.py
  • backend/agents/_run.py
  • backend/agents/health.py
  • backend/agents/social_summary.py
  • backend/agents/study_guide.py
  • backend/main.py
  • backend/routes/social.py
  • backend/routes/study_guide.py
  • backend/tests/test_gemini_test_auth.py
  • backend/tests/test_oneshot_agents.py
  • backend/tests/test_study_guide_routes.py
  • specs/147-oneshot-llm-agents.md
✅ Files skipped from review due to trivial changes (1)
  • specs/147-oneshot-llm-agents.md
🚧 Files skipped from review as they are similar to previous changes (10)
  • backend/agents/_run.py
  • backend/agents/health.py
  • backend/agents/study_guide.py
  • backend/routes/study_guide.py
  • backend/tests/test_study_guide_routes.py
  • backend/routes/social.py
  • backend/main.py
  • backend/tests/test_oneshot_agents.py
  • backend/agents/social_summary.py
  • backend/agents/_providers.py

📝 Walkthrough

Walkthrough

This 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.

Changes

Agent migration

Layer / File(s)Summary
Task defaults and sync bridge
backend/agents/_providers.py, backend/agents/_run.py
Adds study_guide and social_summary to AgentTask and _DEFAULTS, and introduces run_agent_sync for running agent coroutines from sync handlers.
Health probe agent and gemini-test endpoint
backend/agents/health.py, backend/main.py, backend/tests/test_gemini_test_auth.py
Adds health_probe_agent, rewires /api/gemini-test to run it via run_agent_sync, and updates auth/success/failure tests.
Social summary agent and room overview route
backend/agents/social_summary.py, backend/routes/social.py, backend/tests/test_oneshot_agents.py
Adds SocialSummary and social_summary_agent, switches the overview cache-miss path to agent execution, and adds cache-hit/miss/error coverage.
Study guide agent and generation route
backend/agents/study_guide.py, backend/routes/study_guide.py, backend/tests/test_study_guide_routes.py, backend/tests/test_oneshot_agents.py
Adds Topic/StudyGuide and study_guide_agent, rewires generation to agent execution with 502 failure handling, and updates route/output-shape tests.
Migration spec document
specs/147-oneshot-llm-agents.md
Documents the migration requirements and acceptance criteria.

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
Loading

Possibly related issues

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 23.81% which is insufficient. The required threshold is 80.00%.Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check nameStatusExplanation
Title check✅ PassedThe title clearly summarizes the main change: migrating remaining one-shot LLM calls to Pydantic AI agents.
Description check✅ PassedThe description covers the goal, key changes, testing, and related issue, though it doesn't strictly follow the template headings.
Linked Issues check✅ PassedThe three targeted call sites were migrated off direct call_gemini* usage, error handling matches the issue, and remaining callers are legacy fallback and tests.
Out of Scope Changes check✅ PassedThe added modules, bridge helper, tests, and spec document all support the stated migration and do not appear unrelated.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/147-oneshot-llm-agents

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@cloudflare-workers-and-pages

cloudflare-workers-and-pagesBot commented Jul 1, 2026

Copy link
Copy Markdown

Deploying with Cloudflare Workers Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

StatusNameLatest CommitPreview URLUpdated (UTC)
✅ Deployment successful!
View logs
frontend-staging09ce721Commit Preview URL

Branch Preview URL
Jul 01 2026, 02:27 PM

@Jose-Gael-Cruz-Lopez
Jose-Gael-Cruz-Lopezforce-pushed the feat/147-oneshot-llm-agents branch from 1b816ce to 5f0badeCompareJuly 1, 2026 08:38

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
backend/agents/social_summary.py (1)

35-35: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Duplicate prompt-hash boilerplate across agents.

The hashlib.sha256(...).hexdigest()[:12] pattern for _PROMPT_HASH is repeated verbatim in backend/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 value

LGTM! Typed output correctly mirrors the legacy JSON contract, matching result.output.model_dump() usage in routes/study_guide.py. Same prompt-hash duplication note as in agents/social_summary.py applies 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.py
  • backend/agents/_run.py
  • backend/agents/health.py
  • backend/agents/social_summary.py
  • backend/agents/study_guide.py
  • backend/main.py
  • backend/routes/social.py
  • backend/routes/study_guide.py
  • backend/tests/test_gemini_test_auth.py
  • backend/tests/test_oneshot_agents.py
  • backend/tests/test_study_guide_routes.py
  • specs/147-oneshot-llm-agents.md

#147)
Closes an acceptance-#5 gap found in review: the probe-failure branch in
gemini_test (except → {ok:false,error}, still 200) was untested. Adds a case
that raises from health_probe_agent.run and asserts the failure contract.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[P2] Agent migration: remaining one-shot LLM calls (study guide, social, health) → agents/seam

1 participant

@Jose-Gael-Cruz-Lopez
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(agents): migrate remaining one-shot LLM calls to Pydantic AI agents (#147) - #296

Merged
Jose-Gael-Cruz-Lopez merged 201 commits into
mainfrom
feat/147-oneshot-llm-agents
Jul 1, 2026
Merged

feat(agents): migrate remaining one-shot LLM calls to Pydantic AI agents (#147)#296
Jose-Gael-Cruz-Lopez merged 201 commits into
mainfrom
feat/147-oneshot-llm-agents

Conversation

@Jose-Gael-Cruz-Lopez

@Jose-Gael-Cruz-LopezJose-Gael-Cruz-Lopez commented Jul 1, 2026

Copy link
Copy Markdown
Member

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 backend gemini_service callers are the intentional legacy chat fallback (routes/learn.py, retired in the #151 cutover) and tests.

SurfaceBeforeAfter
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

  • Contracts unchanged.StudyGuide/Topic mirror the existing exam/due_date/overview/topics JSON; the route model_dump()s straight into study_guides.content, so cached reads and the frontend are unaffected. /overview and /api/gemini-test response shapes are identical.
  • Study-guide failures now return 502 (per the issue's audit note) instead of a raw 500.
  • Social summary keeps the get_cached_summary → run → save_summary flow and the graceful fallback string (still 200) on agent failure.
  • Health probe runs through the shared GoogleProvider from agents/_providers.py, so a green check means the real agent seam reaches Gemini. Admin-before-spend gate preserved.
  • Sync→async bridge:agents/_run.py::run_agent_sync wraps asyncio.run for the three sync handlers (their surrounding httpx table() access stays synchronous). Handlers are not converted to async def.
  • _providers.py registers study_guide (gemini-2.5-flash) and social_summary (gemini-2.5-flash-lite), both env-overridable via SAPLING_MODEL_*.

Testing

  • Updated test_study_guide_routes.py and test_gemini_test_auth.py to mock the agents; added test_oneshot_agents.py covering the 502 path, social cache-hit/miss/agent-failure, and the StudyGuide → legacy-dict shape.
  • Full backend suite: 829 passed (the 2 test_storage_service failures are pre-existing on main — missing SUPABASE env — verified by stash-and-run).
  • ruff check clean on all changed files.

Out of scope (separate issues): quiz, documents, calendar, flashcards, course_context_service, the learn.py legacy fallback, and deleting gemini_service.py (#151).

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added AI-generated study guides and social room overview summaries using structured, typed outputs.
    • Updated the admin Gemini health check to run through the app’s agent-based flow (preserving {ok, reply} / {ok, error}).
  • Bug Fixes
    • Improved resilience: cache-first behavior remains, and summary generation still falls back to the legacy contract when AI fails.
    • Study guide generation now returns a clearer 502 error when generation cannot be completed.
  • Tests
    • Expanded and updated tests for agent execution, caching behavior, failure handling, and typed output shape serialization.

@coderabbitai

coderabbitaiBot commented Jul 1, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 36b5c5f0-1c9e-4623-ba33-a9861a267129

📥 Commits

Reviewing files that changed from the base of the PR and between 1b816cecd1924d4c086d307a58ca5275e00d11c7 and 09ce721.

📒 Files selected for processing (12)
  • backend/agents/_providers.py
  • backend/agents/_run.py
  • backend/agents/health.py
  • backend/agents/social_summary.py
  • backend/agents/study_guide.py
  • backend/main.py
  • backend/routes/social.py
  • backend/routes/study_guide.py
  • backend/tests/test_gemini_test_auth.py
  • backend/tests/test_oneshot_agents.py
  • backend/tests/test_study_guide_routes.py
  • specs/147-oneshot-llm-agents.md
✅ Files skipped from review due to trivial changes (1)
  • specs/147-oneshot-llm-agents.md
🚧 Files skipped from review as they are similar to previous changes (10)
  • backend/agents/_run.py
  • backend/agents/health.py
  • backend/agents/study_guide.py
  • backend/routes/study_guide.py
  • backend/tests/test_study_guide_routes.py
  • backend/routes/social.py
  • backend/main.py
  • backend/tests/test_oneshot_agents.py
  • backend/agents/social_summary.py
  • backend/agents/_providers.py

📝 Walkthrough

Walkthrough

This 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.

Changes

Agent migration

Layer / File(s)Summary
Task defaults and sync bridge
backend/agents/_providers.py, backend/agents/_run.py
Adds study_guide and social_summary to AgentTask and _DEFAULTS, and introduces run_agent_sync for running agent coroutines from sync handlers.
Health probe agent and gemini-test endpoint
backend/agents/health.py, backend/main.py, backend/tests/test_gemini_test_auth.py
Adds health_probe_agent, rewires /api/gemini-test to run it via run_agent_sync, and updates auth/success/failure tests.
Social summary agent and room overview route
backend/agents/social_summary.py, backend/routes/social.py, backend/tests/test_oneshot_agents.py
Adds SocialSummary and social_summary_agent, switches the overview cache-miss path to agent execution, and adds cache-hit/miss/error coverage.
Study guide agent and generation route
backend/agents/study_guide.py, backend/routes/study_guide.py, backend/tests/test_study_guide_routes.py, backend/tests/test_oneshot_agents.py
Adds Topic/StudyGuide and study_guide_agent, rewires generation to agent execution with 502 failure handling, and updates route/output-shape tests.
Migration spec document
specs/147-oneshot-llm-agents.md
Documents the migration requirements and acceptance criteria.

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
Loading

Possibly related issues

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 23.81% which is insufficient. The required threshold is 80.00%.Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check nameStatusExplanation
Title check✅ PassedThe title clearly summarizes the main change: migrating remaining one-shot LLM calls to Pydantic AI agents.
Description check✅ PassedThe description covers the goal, key changes, testing, and related issue, though it doesn't strictly follow the template headings.
Linked Issues check✅ PassedThe three targeted call sites were migrated off direct call_gemini* usage, error handling matches the issue, and remaining callers are legacy fallback and tests.
Out of Scope Changes check✅ PassedThe added modules, bridge helper, tests, and spec document all support the stated migration and do not appear unrelated.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/147-oneshot-llm-agents

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@cloudflare-workers-and-pages

cloudflare-workers-and-pagesBot commented Jul 1, 2026

Copy link
Copy Markdown

Deploying with Cloudflare Workers Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

StatusNameLatest CommitPreview URLUpdated (UTC)
✅ Deployment successful!
View logs
frontend-staging09ce721Commit Preview URL

Branch Preview URL
Jul 01 2026, 02:27 PM

@Jose-Gael-Cruz-Lopez
Jose-Gael-Cruz-Lopezforce-pushed the feat/147-oneshot-llm-agents branch from 1b816ce to 5f0badeCompareJuly 1, 2026 08:38

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
backend/agents/social_summary.py (1)

35-35: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Duplicate prompt-hash boilerplate across agents.

The hashlib.sha256(...).hexdigest()[:12] pattern for _PROMPT_HASH is repeated verbatim in backend/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 value

LGTM! Typed output correctly mirrors the legacy JSON contract, matching result.output.model_dump() usage in routes/study_guide.py. Same prompt-hash duplication note as in agents/social_summary.py applies 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.py
  • backend/agents/_run.py
  • backend/agents/health.py
  • backend/agents/social_summary.py
  • backend/agents/study_guide.py
  • backend/main.py
  • backend/routes/social.py
  • backend/routes/study_guide.py
  • backend/tests/test_gemini_test_auth.py
  • backend/tests/test_oneshot_agents.py
  • backend/tests/test_study_guide_routes.py
  • specs/147-oneshot-llm-agents.md

#147)
Closes an acceptance-#5 gap found in review: the probe-failure branch in
gemini_test (except → {ok:false,error}, still 200) was untested. Adds a case
that raises from health_probe_agent.run and asserts the failure contract.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[P2] Agent migration: remaining one-shot LLM calls (study guide, social, health) → agents/seam

1 participant

@Jose-Gael-Cruz-Lopez
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(agents): migrate remaining one-shot LLM calls to Pydantic AI agents (#147) - #296

Merged
Jose-Gael-Cruz-Lopez merged 201 commits into
mainfrom
feat/147-oneshot-llm-agents
Jul 1, 2026
Merged

feat(agents): migrate remaining one-shot LLM calls to Pydantic AI agents (#147)#296
Jose-Gael-Cruz-Lopez merged 201 commits into
mainfrom
feat/147-oneshot-llm-agents

Conversation

@Jose-Gael-Cruz-Lopez

@Jose-Gael-Cruz-LopezJose-Gael-Cruz-Lopez commented Jul 1, 2026

Copy link
Copy Markdown
Member

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 backend gemini_service callers are the intentional legacy chat fallback (routes/learn.py, retired in the #151 cutover) and tests.

SurfaceBeforeAfter
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

  • Contracts unchanged.StudyGuide/Topic mirror the existing exam/due_date/overview/topics JSON; the route model_dump()s straight into study_guides.content, so cached reads and the frontend are unaffected. /overview and /api/gemini-test response shapes are identical.
  • Study-guide failures now return 502 (per the issue's audit note) instead of a raw 500.
  • Social summary keeps the get_cached_summary → run → save_summary flow and the graceful fallback string (still 200) on agent failure.
  • Health probe runs through the shared GoogleProvider from agents/_providers.py, so a green check means the real agent seam reaches Gemini. Admin-before-spend gate preserved.
  • Sync→async bridge:agents/_run.py::run_agent_sync wraps asyncio.run for the three sync handlers (their surrounding httpx table() access stays synchronous). Handlers are not converted to async def.
  • _providers.py registers study_guide (gemini-2.5-flash) and social_summary (gemini-2.5-flash-lite), both env-overridable via SAPLING_MODEL_*.

Testing

  • Updated test_study_guide_routes.py and test_gemini_test_auth.py to mock the agents; added test_oneshot_agents.py covering the 502 path, social cache-hit/miss/agent-failure, and the StudyGuide → legacy-dict shape.
  • Full backend suite: 829 passed (the 2 test_storage_service failures are pre-existing on main — missing SUPABASE env — verified by stash-and-run).
  • ruff check clean on all changed files.

Out of scope (separate issues): quiz, documents, calendar, flashcards, course_context_service, the learn.py legacy fallback, and deleting gemini_service.py (#151).

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added AI-generated study guides and social room overview summaries using structured, typed outputs.
    • Updated the admin Gemini health check to run through the app’s agent-based flow (preserving {ok, reply} / {ok, error}).
  • Bug Fixes
    • Improved resilience: cache-first behavior remains, and summary generation still falls back to the legacy contract when AI fails.
    • Study guide generation now returns a clearer 502 error when generation cannot be completed.
  • Tests
    • Expanded and updated tests for agent execution, caching behavior, failure handling, and typed output shape serialization.

@coderabbitai

coderabbitaiBot commented Jul 1, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 36b5c5f0-1c9e-4623-ba33-a9861a267129

📥 Commits

Reviewing files that changed from the base of the PR and between 1b816cecd1924d4c086d307a58ca5275e00d11c7 and 09ce721.

📒 Files selected for processing (12)
  • backend/agents/_providers.py
  • backend/agents/_run.py
  • backend/agents/health.py
  • backend/agents/social_summary.py
  • backend/agents/study_guide.py
  • backend/main.py
  • backend/routes/social.py
  • backend/routes/study_guide.py
  • backend/tests/test_gemini_test_auth.py
  • backend/tests/test_oneshot_agents.py
  • backend/tests/test_study_guide_routes.py
  • specs/147-oneshot-llm-agents.md
✅ Files skipped from review due to trivial changes (1)
  • specs/147-oneshot-llm-agents.md
🚧 Files skipped from review as they are similar to previous changes (10)
  • backend/agents/_run.py
  • backend/agents/health.py
  • backend/agents/study_guide.py
  • backend/routes/study_guide.py
  • backend/tests/test_study_guide_routes.py
  • backend/routes/social.py
  • backend/main.py
  • backend/tests/test_oneshot_agents.py
  • backend/agents/social_summary.py
  • backend/agents/_providers.py

📝 Walkthrough

Walkthrough

This 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.

Changes

Agent migration

Layer / File(s)Summary
Task defaults and sync bridge
backend/agents/_providers.py, backend/agents/_run.py
Adds study_guide and social_summary to AgentTask and _DEFAULTS, and introduces run_agent_sync for running agent coroutines from sync handlers.
Health probe agent and gemini-test endpoint
backend/agents/health.py, backend/main.py, backend/tests/test_gemini_test_auth.py
Adds health_probe_agent, rewires /api/gemini-test to run it via run_agent_sync, and updates auth/success/failure tests.
Social summary agent and room overview route
backend/agents/social_summary.py, backend/routes/social.py, backend/tests/test_oneshot_agents.py
Adds SocialSummary and social_summary_agent, switches the overview cache-miss path to agent execution, and adds cache-hit/miss/error coverage.
Study guide agent and generation route
backend/agents/study_guide.py, backend/routes/study_guide.py, backend/tests/test_study_guide_routes.py, backend/tests/test_oneshot_agents.py
Adds Topic/StudyGuide and study_guide_agent, rewires generation to agent execution with 502 failure handling, and updates route/output-shape tests.
Migration spec document
specs/147-oneshot-llm-agents.md
Documents the migration requirements and acceptance criteria.

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
Loading

Possibly related issues

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 23.81% which is insufficient. The required threshold is 80.00%.Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check nameStatusExplanation
Title check✅ PassedThe title clearly summarizes the main change: migrating remaining one-shot LLM calls to Pydantic AI agents.
Description check✅ PassedThe description covers the goal, key changes, testing, and related issue, though it doesn't strictly follow the template headings.
Linked Issues check✅ PassedThe three targeted call sites were migrated off direct call_gemini* usage, error handling matches the issue, and remaining callers are legacy fallback and tests.
Out of Scope Changes check✅ PassedThe added modules, bridge helper, tests, and spec document all support the stated migration and do not appear unrelated.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/147-oneshot-llm-agents

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@cloudflare-workers-and-pages

cloudflare-workers-and-pagesBot commented Jul 1, 2026

Copy link
Copy Markdown

Deploying with Cloudflare Workers Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

StatusNameLatest CommitPreview URLUpdated (UTC)
✅ Deployment successful!
View logs
frontend-staging09ce721Commit Preview URL

Branch Preview URL
Jul 01 2026, 02:27 PM

@Jose-Gael-Cruz-Lopez
Jose-Gael-Cruz-Lopezforce-pushed the feat/147-oneshot-llm-agents branch from 1b816ce to 5f0badeCompareJuly 1, 2026 08:38

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
backend/agents/social_summary.py (1)

35-35: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Duplicate prompt-hash boilerplate across agents.

The hashlib.sha256(...).hexdigest()[:12] pattern for _PROMPT_HASH is repeated verbatim in backend/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 value

LGTM! Typed output correctly mirrors the legacy JSON contract, matching result.output.model_dump() usage in routes/study_guide.py. Same prompt-hash duplication note as in agents/social_summary.py applies 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.py
  • backend/agents/_run.py
  • backend/agents/health.py
  • backend/agents/social_summary.py
  • backend/agents/study_guide.py
  • backend/main.py
  • backend/routes/social.py
  • backend/routes/study_guide.py
  • backend/tests/test_gemini_test_auth.py
  • backend/tests/test_oneshot_agents.py
  • backend/tests/test_study_guide_routes.py
  • specs/147-oneshot-llm-agents.md

#147)
Closes an acceptance-#5 gap found in review: the probe-failure branch in
gemini_test (except → {ok:false,error}, still 200) was untested. Adds a case
that raises from health_probe_agent.run and asserts the failure contract.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[P2] Agent migration: remaining one-shot LLM calls (study guide, social, health) → agents/seam

1 participant

@Jose-Gael-Cruz-Lopez
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

feat(agents): migrate remaining one-shot LLM calls to Pydantic AI agents (#147) - #296

Merged
Jose-Gael-Cruz-Lopez merged 201 commits into
mainfrom
feat/147-oneshot-llm-agents
Jul 1, 2026
Merged

feat(agents): migrate remaining one-shot LLM calls to Pydantic AI agents (#147)#296
Jose-Gael-Cruz-Lopez merged 201 commits into
mainfrom
feat/147-oneshot-llm-agents

Conversation

@Jose-Gael-Cruz-Lopez

@Jose-Gael-Cruz-LopezJose-Gael-Cruz-Lopez commented Jul 1, 2026

Copy link
Copy Markdown
Member

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 backend gemini_service callers are the intentional legacy chat fallback (routes/learn.py, retired in the #151 cutover) and tests.

SurfaceBeforeAfter
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

  • Contracts unchanged.StudyGuide/Topic mirror the existing exam/due_date/overview/topics JSON; the route model_dump()s straight into study_guides.content, so cached reads and the frontend are unaffected. /overview and /api/gemini-test response shapes are identical.
  • Study-guide failures now return 502 (per the issue's audit note) instead of a raw 500.
  • Social summary keeps the get_cached_summary → run → save_summary flow and the graceful fallback string (still 200) on agent failure.
  • Health probe runs through the shared GoogleProvider from agents/_providers.py, so a green check means the real agent seam reaches Gemini. Admin-before-spend gate preserved.
  • Sync→async bridge:agents/_run.py::run_agent_sync wraps asyncio.run for the three sync handlers (their surrounding httpx table() access stays synchronous). Handlers are not converted to async def.
  • _providers.py registers study_guide (gemini-2.5-flash) and social_summary (gemini-2.5-flash-lite), both env-overridable via SAPLING_MODEL_*.

Testing

  • Updated test_study_guide_routes.py and test_gemini_test_auth.py to mock the agents; added test_oneshot_agents.py covering the 502 path, social cache-hit/miss/agent-failure, and the StudyGuide → legacy-dict shape.
  • Full backend suite: 829 passed (the 2 test_storage_service failures are pre-existing on main — missing SUPABASE env — verified by stash-and-run).
  • ruff check clean on all changed files.

Out of scope (separate issues): quiz, documents, calendar, flashcards, course_context_service, the learn.py legacy fallback, and deleting gemini_service.py (#151).

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added AI-generated study guides and social room overview summaries using structured, typed outputs.
    • Updated the admin Gemini health check to run through the app’s agent-based flow (preserving {ok, reply} / {ok, error}).
  • Bug Fixes
    • Improved resilience: cache-first behavior remains, and summary generation still falls back to the legacy contract when AI fails.
    • Study guide generation now returns a clearer 502 error when generation cannot be completed.
  • Tests
    • Expanded and updated tests for agent execution, caching behavior, failure handling, and typed output shape serialization.

@coderabbitai

coderabbitaiBot commented Jul 1, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 36b5c5f0-1c9e-4623-ba33-a9861a267129

📥 Commits

Reviewing files that changed from the base of the PR and between 1b816cecd1924d4c086d307a58ca5275e00d11c7 and 09ce721.

📒 Files selected for processing (12)
  • backend/agents/_providers.py
  • backend/agents/_run.py
  • backend/agents/health.py
  • backend/agents/social_summary.py
  • backend/agents/study_guide.py
  • backend/main.py
  • backend/routes/social.py
  • backend/routes/study_guide.py
  • backend/tests/test_gemini_test_auth.py
  • backend/tests/test_oneshot_agents.py
  • backend/tests/test_study_guide_routes.py
  • specs/147-oneshot-llm-agents.md
✅ Files skipped from review due to trivial changes (1)
  • specs/147-oneshot-llm-agents.md
🚧 Files skipped from review as they are similar to previous changes (10)
  • backend/agents/_run.py
  • backend/agents/health.py
  • backend/agents/study_guide.py
  • backend/routes/study_guide.py
  • backend/tests/test_study_guide_routes.py
  • backend/routes/social.py
  • backend/main.py
  • backend/tests/test_oneshot_agents.py
  • backend/agents/social_summary.py
  • backend/agents/_providers.py

📝 Walkthrough

Walkthrough

This 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.

Changes

Agent migration

Layer / File(s)Summary
Task defaults and sync bridge
backend/agents/_providers.py, backend/agents/_run.py
Adds study_guide and social_summary to AgentTask and _DEFAULTS, and introduces run_agent_sync for running agent coroutines from sync handlers.
Health probe agent and gemini-test endpoint
backend/agents/health.py, backend/main.py, backend/tests/test_gemini_test_auth.py
Adds health_probe_agent, rewires /api/gemini-test to run it via run_agent_sync, and updates auth/success/failure tests.
Social summary agent and room overview route
backend/agents/social_summary.py, backend/routes/social.py, backend/tests/test_oneshot_agents.py
Adds SocialSummary and social_summary_agent, switches the overview cache-miss path to agent execution, and adds cache-hit/miss/error coverage.
Study guide agent and generation route
backend/agents/study_guide.py, backend/routes/study_guide.py, backend/tests/test_study_guide_routes.py, backend/tests/test_oneshot_agents.py
Adds Topic/StudyGuide and study_guide_agent, rewires generation to agent execution with 502 failure handling, and updates route/output-shape tests.
Migration spec document
specs/147-oneshot-llm-agents.md
Documents the migration requirements and acceptance criteria.

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
Loading

Possibly related issues

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 23.81% which is insufficient. The required threshold is 80.00%.Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check nameStatusExplanation
Title check✅ PassedThe title clearly summarizes the main change: migrating remaining one-shot LLM calls to Pydantic AI agents.
Description check✅ PassedThe description covers the goal, key changes, testing, and related issue, though it doesn't strictly follow the template headings.
Linked Issues check✅ PassedThe three targeted call sites were migrated off direct call_gemini* usage, error handling matches the issue, and remaining callers are legacy fallback and tests.
Out of Scope Changes check✅ PassedThe added modules, bridge helper, tests, and spec document all support the stated migration and do not appear unrelated.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/147-oneshot-llm-agents

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@cloudflare-workers-and-pages

cloudflare-workers-and-pagesBot commented Jul 1, 2026

Copy link
Copy Markdown

Deploying with Cloudflare Workers Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

StatusNameLatest CommitPreview URLUpdated (UTC)
✅ Deployment successful!
View logs
frontend-staging09ce721Commit Preview URL

Branch Preview URL
Jul 01 2026, 02:27 PM

@Jose-Gael-Cruz-Lopez
Jose-Gael-Cruz-Lopezforce-pushed the feat/147-oneshot-llm-agents branch from 1b816ce to 5f0badeCompareJuly 1, 2026 08:38

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
backend/agents/social_summary.py (1)

35-35: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Duplicate prompt-hash boilerplate across agents.

The hashlib.sha256(...).hexdigest()[:12] pattern for _PROMPT_HASH is repeated verbatim in backend/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 value

LGTM! Typed output correctly mirrors the legacy JSON contract, matching result.output.model_dump() usage in routes/study_guide.py. Same prompt-hash duplication note as in agents/social_summary.py applies 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.py
  • backend/agents/_run.py
  • backend/agents/health.py
  • backend/agents/social_summary.py
  • backend/agents/study_guide.py
  • backend/main.py
  • backend/routes/social.py
  • backend/routes/study_guide.py
  • backend/tests/test_gemini_test_auth.py
  • backend/tests/test_oneshot_agents.py
  • backend/tests/test_study_guide_routes.py
  • specs/147-oneshot-llm-agents.md

#147)
Closes an acceptance-#5 gap found in review: the probe-failure branch in
gemini_test (except → {ok:false,error}, still 200) was untested. Adds a case
that raises from health_probe_agent.run and asserts the failure contract.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[P2] Agent migration: remaining one-shot LLM calls (study guide, social, health) → agents/seam

1 participant

@Jose-Gael-Cruz-Lopez
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(agents): migrate remaining one-shot LLM calls to Pydantic AI agents (#147) - #296

Merged
Jose-Gael-Cruz-Lopez merged 201 commits into
mainfrom
feat/147-oneshot-llm-agents
Jul 1, 2026
Merged

feat(agents): migrate remaining one-shot LLM calls to Pydantic AI agents (#147)#296
Jose-Gael-Cruz-Lopez merged 201 commits into
mainfrom
feat/147-oneshot-llm-agents

Conversation

@Jose-Gael-Cruz-Lopez

@Jose-Gael-Cruz-LopezJose-Gael-Cruz-Lopez commented Jul 1, 2026

Copy link
Copy Markdown
Member

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 backend gemini_service callers are the intentional legacy chat fallback (routes/learn.py, retired in the #151 cutover) and tests.

SurfaceBeforeAfter
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

  • Contracts unchanged.StudyGuide/Topic mirror the existing exam/due_date/overview/topics JSON; the route model_dump()s straight into study_guides.content, so cached reads and the frontend are unaffected. /overview and /api/gemini-test response shapes are identical.
  • Study-guide failures now return 502 (per the issue's audit note) instead of a raw 500.
  • Social summary keeps the get_cached_summary → run → save_summary flow and the graceful fallback string (still 200) on agent failure.
  • Health probe runs through the shared GoogleProvider from agents/_providers.py, so a green check means the real agent seam reaches Gemini. Admin-before-spend gate preserved.
  • Sync→async bridge:agents/_run.py::run_agent_sync wraps asyncio.run for the three sync handlers (their surrounding httpx table() access stays synchronous). Handlers are not converted to async def.
  • _providers.py registers study_guide (gemini-2.5-flash) and social_summary (gemini-2.5-flash-lite), both env-overridable via SAPLING_MODEL_*.

Testing

  • Updated test_study_guide_routes.py and test_gemini_test_auth.py to mock the agents; added test_oneshot_agents.py covering the 502 path, social cache-hit/miss/agent-failure, and the StudyGuide → legacy-dict shape.
  • Full backend suite: 829 passed (the 2 test_storage_service failures are pre-existing on main — missing SUPABASE env — verified by stash-and-run).
  • ruff check clean on all changed files.

Out of scope (separate issues): quiz, documents, calendar, flashcards, course_context_service, the learn.py legacy fallback, and deleting gemini_service.py (#151).

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added AI-generated study guides and social room overview summaries using structured, typed outputs.
    • Updated the admin Gemini health check to run through the app’s agent-based flow (preserving {ok, reply} / {ok, error}).
  • Bug Fixes
    • Improved resilience: cache-first behavior remains, and summary generation still falls back to the legacy contract when AI fails.
    • Study guide generation now returns a clearer 502 error when generation cannot be completed.
  • Tests
    • Expanded and updated tests for agent execution, caching behavior, failure handling, and typed output shape serialization.

@coderabbitai

coderabbitaiBot commented Jul 1, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 36b5c5f0-1c9e-4623-ba33-a9861a267129

📥 Commits

Reviewing files that changed from the base of the PR and between 1b816cecd1924d4c086d307a58ca5275e00d11c7 and 09ce721.

📒 Files selected for processing (12)
  • backend/agents/_providers.py
  • backend/agents/_run.py
  • backend/agents/health.py
  • backend/agents/social_summary.py
  • backend/agents/study_guide.py
  • backend/main.py
  • backend/routes/social.py
  • backend/routes/study_guide.py
  • backend/tests/test_gemini_test_auth.py
  • backend/tests/test_oneshot_agents.py
  • backend/tests/test_study_guide_routes.py
  • specs/147-oneshot-llm-agents.md
✅ Files skipped from review due to trivial changes (1)
  • specs/147-oneshot-llm-agents.md
🚧 Files skipped from review as they are similar to previous changes (10)
  • backend/agents/_run.py
  • backend/agents/health.py
  • backend/agents/study_guide.py
  • backend/routes/study_guide.py
  • backend/tests/test_study_guide_routes.py
  • backend/routes/social.py
  • backend/main.py
  • backend/tests/test_oneshot_agents.py
  • backend/agents/social_summary.py
  • backend/agents/_providers.py

📝 Walkthrough

Walkthrough

This 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.

Changes

Agent migration

Layer / File(s)Summary
Task defaults and sync bridge
backend/agents/_providers.py, backend/agents/_run.py
Adds study_guide and social_summary to AgentTask and _DEFAULTS, and introduces run_agent_sync for running agent coroutines from sync handlers.
Health probe agent and gemini-test endpoint
backend/agents/health.py, backend/main.py, backend/tests/test_gemini_test_auth.py
Adds health_probe_agent, rewires /api/gemini-test to run it via run_agent_sync, and updates auth/success/failure tests.
Social summary agent and room overview route
backend/agents/social_summary.py, backend/routes/social.py, backend/tests/test_oneshot_agents.py
Adds SocialSummary and social_summary_agent, switches the overview cache-miss path to agent execution, and adds cache-hit/miss/error coverage.
Study guide agent and generation route
backend/agents/study_guide.py, backend/routes/study_guide.py, backend/tests/test_study_guide_routes.py, backend/tests/test_oneshot_agents.py
Adds Topic/StudyGuide and study_guide_agent, rewires generation to agent execution with 502 failure handling, and updates route/output-shape tests.
Migration spec document
specs/147-oneshot-llm-agents.md
Documents the migration requirements and acceptance criteria.

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
Loading

Possibly related issues

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 23.81% which is insufficient. The required threshold is 80.00%.Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check nameStatusExplanation
Title check✅ PassedThe title clearly summarizes the main change: migrating remaining one-shot LLM calls to Pydantic AI agents.
Description check✅ PassedThe description covers the goal, key changes, testing, and related issue, though it doesn't strictly follow the template headings.
Linked Issues check✅ PassedThe three targeted call sites were migrated off direct call_gemini* usage, error handling matches the issue, and remaining callers are legacy fallback and tests.
Out of Scope Changes check✅ PassedThe added modules, bridge helper, tests, and spec document all support the stated migration and do not appear unrelated.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/147-oneshot-llm-agents

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@cloudflare-workers-and-pages

cloudflare-workers-and-pagesBot commented Jul 1, 2026

Copy link
Copy Markdown

Deploying with Cloudflare Workers Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

StatusNameLatest CommitPreview URLUpdated (UTC)
✅ Deployment successful!
View logs
frontend-staging09ce721Commit Preview URL

Branch Preview URL
Jul 01 2026, 02:27 PM

@Jose-Gael-Cruz-Lopez
Jose-Gael-Cruz-Lopezforce-pushed the feat/147-oneshot-llm-agents branch from 1b816ce to 5f0badeCompareJuly 1, 2026 08:38

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
backend/agents/social_summary.py (1)

35-35: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Duplicate prompt-hash boilerplate across agents.

The hashlib.sha256(...).hexdigest()[:12] pattern for _PROMPT_HASH is repeated verbatim in backend/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 value

LGTM! Typed output correctly mirrors the legacy JSON contract, matching result.output.model_dump() usage in routes/study_guide.py. Same prompt-hash duplication note as in agents/social_summary.py applies 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.py
  • backend/agents/_run.py
  • backend/agents/health.py
  • backend/agents/social_summary.py
  • backend/agents/study_guide.py
  • backend/main.py
  • backend/routes/social.py
  • backend/routes/study_guide.py
  • backend/tests/test_gemini_test_auth.py
  • backend/tests/test_oneshot_agents.py
  • backend/tests/test_study_guide_routes.py
  • specs/147-oneshot-llm-agents.md

#147)
Closes an acceptance-#5 gap found in review: the probe-failure branch in
gemini_test (except → {ok:false,error}, still 200) was untested. Adds a case
that raises from health_probe_agent.run and asserts the failure contract.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[P2] Agent migration: remaining one-shot LLM calls (study guide, social, health) → agents/seam

1 participant

@Jose-Gael-Cruz-Lopez
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(agents): migrate remaining one-shot LLM calls to Pydantic AI agents (#147) - #296

Merged
Jose-Gael-Cruz-Lopez merged 201 commits into
mainfrom
feat/147-oneshot-llm-agents
Jul 1, 2026
Merged

feat(agents): migrate remaining one-shot LLM calls to Pydantic AI agents (#147)#296
Jose-Gael-Cruz-Lopez merged 201 commits into
mainfrom
feat/147-oneshot-llm-agents

Conversation

@Jose-Gael-Cruz-Lopez

@Jose-Gael-Cruz-LopezJose-Gael-Cruz-Lopez commented Jul 1, 2026

Copy link
Copy Markdown
Member

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 backend gemini_service callers are the intentional legacy chat fallback (routes/learn.py, retired in the #151 cutover) and tests.

SurfaceBeforeAfter
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

  • Contracts unchanged.StudyGuide/Topic mirror the existing exam/due_date/overview/topics JSON; the route model_dump()s straight into study_guides.content, so cached reads and the frontend are unaffected. /overview and /api/gemini-test response shapes are identical.
  • Study-guide failures now return 502 (per the issue's audit note) instead of a raw 500.
  • Social summary keeps the get_cached_summary → run → save_summary flow and the graceful fallback string (still 200) on agent failure.
  • Health probe runs through the shared GoogleProvider from agents/_providers.py, so a green check means the real agent seam reaches Gemini. Admin-before-spend gate preserved.
  • Sync→async bridge:agents/_run.py::run_agent_sync wraps asyncio.run for the three sync handlers (their surrounding httpx table() access stays synchronous). Handlers are not converted to async def.
  • _providers.py registers study_guide (gemini-2.5-flash) and social_summary (gemini-2.5-flash-lite), both env-overridable via SAPLING_MODEL_*.

Testing

  • Updated test_study_guide_routes.py and test_gemini_test_auth.py to mock the agents; added test_oneshot_agents.py covering the 502 path, social cache-hit/miss/agent-failure, and the StudyGuide → legacy-dict shape.
  • Full backend suite: 829 passed (the 2 test_storage_service failures are pre-existing on main — missing SUPABASE env — verified by stash-and-run).
  • ruff check clean on all changed files.

Out of scope (separate issues): quiz, documents, calendar, flashcards, course_context_service, the learn.py legacy fallback, and deleting gemini_service.py (#151).

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added AI-generated study guides and social room overview summaries using structured, typed outputs.
    • Updated the admin Gemini health check to run through the app’s agent-based flow (preserving {ok, reply} / {ok, error}).
  • Bug Fixes
    • Improved resilience: cache-first behavior remains, and summary generation still falls back to the legacy contract when AI fails.
    • Study guide generation now returns a clearer 502 error when generation cannot be completed.
  • Tests
    • Expanded and updated tests for agent execution, caching behavior, failure handling, and typed output shape serialization.

@coderabbitai

coderabbitaiBot commented Jul 1, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 36b5c5f0-1c9e-4623-ba33-a9861a267129

📥 Commits

Reviewing files that changed from the base of the PR and between 1b816cecd1924d4c086d307a58ca5275e00d11c7 and 09ce721.

📒 Files selected for processing (12)
  • backend/agents/_providers.py
  • backend/agents/_run.py
  • backend/agents/health.py
  • backend/agents/social_summary.py
  • backend/agents/study_guide.py
  • backend/main.py
  • backend/routes/social.py
  • backend/routes/study_guide.py
  • backend/tests/test_gemini_test_auth.py
  • backend/tests/test_oneshot_agents.py
  • backend/tests/test_study_guide_routes.py
  • specs/147-oneshot-llm-agents.md
✅ Files skipped from review due to trivial changes (1)
  • specs/147-oneshot-llm-agents.md
🚧 Files skipped from review as they are similar to previous changes (10)
  • backend/agents/_run.py
  • backend/agents/health.py
  • backend/agents/study_guide.py
  • backend/routes/study_guide.py
  • backend/tests/test_study_guide_routes.py
  • backend/routes/social.py
  • backend/main.py
  • backend/tests/test_oneshot_agents.py
  • backend/agents/social_summary.py
  • backend/agents/_providers.py

📝 Walkthrough

Walkthrough

This 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.

Changes

Agent migration

Layer / File(s)Summary
Task defaults and sync bridge
backend/agents/_providers.py, backend/agents/_run.py
Adds study_guide and social_summary to AgentTask and _DEFAULTS, and introduces run_agent_sync for running agent coroutines from sync handlers.
Health probe agent and gemini-test endpoint
backend/agents/health.py, backend/main.py, backend/tests/test_gemini_test_auth.py
Adds health_probe_agent, rewires /api/gemini-test to run it via run_agent_sync, and updates auth/success/failure tests.
Social summary agent and room overview route
backend/agents/social_summary.py, backend/routes/social.py, backend/tests/test_oneshot_agents.py
Adds SocialSummary and social_summary_agent, switches the overview cache-miss path to agent execution, and adds cache-hit/miss/error coverage.
Study guide agent and generation route
backend/agents/study_guide.py, backend/routes/study_guide.py, backend/tests/test_study_guide_routes.py, backend/tests/test_oneshot_agents.py
Adds Topic/StudyGuide and study_guide_agent, rewires generation to agent execution with 502 failure handling, and updates route/output-shape tests.
Migration spec document
specs/147-oneshot-llm-agents.md
Documents the migration requirements and acceptance criteria.

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
Loading

Possibly related issues

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 23.81% which is insufficient. The required threshold is 80.00%.Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check nameStatusExplanation
Title check✅ PassedThe title clearly summarizes the main change: migrating remaining one-shot LLM calls to Pydantic AI agents.
Description check✅ PassedThe description covers the goal, key changes, testing, and related issue, though it doesn't strictly follow the template headings.
Linked Issues check✅ PassedThe three targeted call sites were migrated off direct call_gemini* usage, error handling matches the issue, and remaining callers are legacy fallback and tests.
Out of Scope Changes check✅ PassedThe added modules, bridge helper, tests, and spec document all support the stated migration and do not appear unrelated.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/147-oneshot-llm-agents

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@cloudflare-workers-and-pages

cloudflare-workers-and-pagesBot commented Jul 1, 2026

Copy link
Copy Markdown

Deploying with Cloudflare Workers Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

StatusNameLatest CommitPreview URLUpdated (UTC)
✅ Deployment successful!
View logs
frontend-staging09ce721Commit Preview URL

Branch Preview URL
Jul 01 2026, 02:27 PM

@Jose-Gael-Cruz-Lopez
Jose-Gael-Cruz-Lopezforce-pushed the feat/147-oneshot-llm-agents branch from 1b816ce to 5f0badeCompareJuly 1, 2026 08:38

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
backend/agents/social_summary.py (1)

35-35: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Duplicate prompt-hash boilerplate across agents.

The hashlib.sha256(...).hexdigest()[:12] pattern for _PROMPT_HASH is repeated verbatim in backend/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 value

LGTM! Typed output correctly mirrors the legacy JSON contract, matching result.output.model_dump() usage in routes/study_guide.py. Same prompt-hash duplication note as in agents/social_summary.py applies 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.py
  • backend/agents/_run.py
  • backend/agents/health.py
  • backend/agents/social_summary.py
  • backend/agents/study_guide.py
  • backend/main.py
  • backend/routes/social.py
  • backend/routes/study_guide.py
  • backend/tests/test_gemini_test_auth.py
  • backend/tests/test_oneshot_agents.py
  • backend/tests/test_study_guide_routes.py
  • specs/147-oneshot-llm-agents.md

#147)
Closes an acceptance-#5 gap found in review: the probe-failure branch in
gemini_test (except → {ok:false,error}, still 200) was untested. Adds a case
that raises from health_probe_agent.run and asserts the failure contract.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[P2] Agent migration: remaining one-shot LLM calls (study guide, social, health) → agents/seam

1 participant

@Jose-Gael-Cruz-Lopez
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

feat(agents): migrate remaining one-shot LLM calls to Pydantic AI agents (#147) - #296

Merged
Jose-Gael-Cruz-Lopez merged 201 commits into
mainfrom
feat/147-oneshot-llm-agents
Jul 1, 2026
Merged

feat(agents): migrate remaining one-shot LLM calls to Pydantic AI agents (#147)#296
Jose-Gael-Cruz-Lopez merged 201 commits into
mainfrom
feat/147-oneshot-llm-agents

Conversation

@Jose-Gael-Cruz-Lopez

@Jose-Gael-Cruz-LopezJose-Gael-Cruz-Lopez commented Jul 1, 2026

Copy link
Copy Markdown
Member

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 backend gemini_service callers are the intentional legacy chat fallback (routes/learn.py, retired in the #151 cutover) and tests.

SurfaceBeforeAfter
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

  • Contracts unchanged.StudyGuide/Topic mirror the existing exam/due_date/overview/topics JSON; the route model_dump()s straight into study_guides.content, so cached reads and the frontend are unaffected. /overview and /api/gemini-test response shapes are identical.
  • Study-guide failures now return 502 (per the issue's audit note) instead of a raw 500.
  • Social summary keeps the get_cached_summary → run → save_summary flow and the graceful fallback string (still 200) on agent failure.
  • Health probe runs through the shared GoogleProvider from agents/_providers.py, so a green check means the real agent seam reaches Gemini. Admin-before-spend gate preserved.
  • Sync→async bridge:agents/_run.py::run_agent_sync wraps asyncio.run for the three sync handlers (their surrounding httpx table() access stays synchronous). Handlers are not converted to async def.
  • _providers.py registers study_guide (gemini-2.5-flash) and social_summary (gemini-2.5-flash-lite), both env-overridable via SAPLING_MODEL_*.

Testing

  • Updated test_study_guide_routes.py and test_gemini_test_auth.py to mock the agents; added test_oneshot_agents.py covering the 502 path, social cache-hit/miss/agent-failure, and the StudyGuide → legacy-dict shape.
  • Full backend suite: 829 passed (the 2 test_storage_service failures are pre-existing on main — missing SUPABASE env — verified by stash-and-run).
  • ruff check clean on all changed files.

Out of scope (separate issues): quiz, documents, calendar, flashcards, course_context_service, the learn.py legacy fallback, and deleting gemini_service.py (#151).

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added AI-generated study guides and social room overview summaries using structured, typed outputs.
    • Updated the admin Gemini health check to run through the app’s agent-based flow (preserving {ok, reply} / {ok, error}).
  • Bug Fixes
    • Improved resilience: cache-first behavior remains, and summary generation still falls back to the legacy contract when AI fails.
    • Study guide generation now returns a clearer 502 error when generation cannot be completed.
  • Tests
    • Expanded and updated tests for agent execution, caching behavior, failure handling, and typed output shape serialization.

@coderabbitai

coderabbitaiBot commented Jul 1, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 36b5c5f0-1c9e-4623-ba33-a9861a267129

📥 Commits

Reviewing files that changed from the base of the PR and between 1b816cecd1924d4c086d307a58ca5275e00d11c7 and 09ce721.

📒 Files selected for processing (12)
  • backend/agents/_providers.py
  • backend/agents/_run.py
  • backend/agents/health.py
  • backend/agents/social_summary.py
  • backend/agents/study_guide.py
  • backend/main.py
  • backend/routes/social.py
  • backend/routes/study_guide.py
  • backend/tests/test_gemini_test_auth.py
  • backend/tests/test_oneshot_agents.py
  • backend/tests/test_study_guide_routes.py
  • specs/147-oneshot-llm-agents.md
✅ Files skipped from review due to trivial changes (1)
  • specs/147-oneshot-llm-agents.md
🚧 Files skipped from review as they are similar to previous changes (10)
  • backend/agents/_run.py
  • backend/agents/health.py
  • backend/agents/study_guide.py
  • backend/routes/study_guide.py
  • backend/tests/test_study_guide_routes.py
  • backend/routes/social.py
  • backend/main.py
  • backend/tests/test_oneshot_agents.py
  • backend/agents/social_summary.py
  • backend/agents/_providers.py

📝 Walkthrough

Walkthrough

This 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.

Changes

Agent migration

Layer / File(s)Summary
Task defaults and sync bridge
backend/agents/_providers.py, backend/agents/_run.py
Adds study_guide and social_summary to AgentTask and _DEFAULTS, and introduces run_agent_sync for running agent coroutines from sync handlers.
Health probe agent and gemini-test endpoint
backend/agents/health.py, backend/main.py, backend/tests/test_gemini_test_auth.py
Adds health_probe_agent, rewires /api/gemini-test to run it via run_agent_sync, and updates auth/success/failure tests.
Social summary agent and room overview route
backend/agents/social_summary.py, backend/routes/social.py, backend/tests/test_oneshot_agents.py
Adds SocialSummary and social_summary_agent, switches the overview cache-miss path to agent execution, and adds cache-hit/miss/error coverage.
Study guide agent and generation route
backend/agents/study_guide.py, backend/routes/study_guide.py, backend/tests/test_study_guide_routes.py, backend/tests/test_oneshot_agents.py
Adds Topic/StudyGuide and study_guide_agent, rewires generation to agent execution with 502 failure handling, and updates route/output-shape tests.
Migration spec document
specs/147-oneshot-llm-agents.md
Documents the migration requirements and acceptance criteria.

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
Loading

Possibly related issues

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 23.81% which is insufficient. The required threshold is 80.00%.Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check nameStatusExplanation
Title check✅ PassedThe title clearly summarizes the main change: migrating remaining one-shot LLM calls to Pydantic AI agents.
Description check✅ PassedThe description covers the goal, key changes, testing, and related issue, though it doesn't strictly follow the template headings.
Linked Issues check✅ PassedThe three targeted call sites were migrated off direct call_gemini* usage, error handling matches the issue, and remaining callers are legacy fallback and tests.
Out of Scope Changes check✅ PassedThe added modules, bridge helper, tests, and spec document all support the stated migration and do not appear unrelated.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/147-oneshot-llm-agents

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@cloudflare-workers-and-pages

cloudflare-workers-and-pagesBot commented Jul 1, 2026

Copy link
Copy Markdown

Deploying with Cloudflare Workers Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

StatusNameLatest CommitPreview URLUpdated (UTC)
✅ Deployment successful!
View logs
frontend-staging09ce721Commit Preview URL

Branch Preview URL
Jul 01 2026, 02:27 PM

@Jose-Gael-Cruz-Lopez
Jose-Gael-Cruz-Lopezforce-pushed the feat/147-oneshot-llm-agents branch from 1b816ce to 5f0badeCompareJuly 1, 2026 08:38

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
backend/agents/social_summary.py (1)

35-35: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Duplicate prompt-hash boilerplate across agents.

The hashlib.sha256(...).hexdigest()[:12] pattern for _PROMPT_HASH is repeated verbatim in backend/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 value

LGTM! Typed output correctly mirrors the legacy JSON contract, matching result.output.model_dump() usage in routes/study_guide.py. Same prompt-hash duplication note as in agents/social_summary.py applies 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.py
  • backend/agents/_run.py
  • backend/agents/health.py
  • backend/agents/social_summary.py
  • backend/agents/study_guide.py
  • backend/main.py
  • backend/routes/social.py
  • backend/routes/study_guide.py
  • backend/tests/test_gemini_test_auth.py
  • backend/tests/test_oneshot_agents.py
  • backend/tests/test_study_guide_routes.py
  • specs/147-oneshot-llm-agents.md

#147)
Closes an acceptance-#5 gap found in review: the probe-failure branch in
gemini_test (except → {ok:false,error}, still 200) was untested. Adds a case
that raises from health_probe_agent.run and asserts the failure contract.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[P2] Agent migration: remaining one-shot LLM calls (study guide, social, health) → agents/seam

1 participant

@Jose-Gael-Cruz-Lopez