Skip to content

refactor: unwrap response util#1036

Merged
leonardmq merged 5 commits intosfierro/optimize-featurefrom
leonard/kil-414-refactor-use-asyncio-detailed-and-check-error-response
Feb 17, 2026
Merged

refactor: unwrap response util#1036
leonardmq merged 5 commits intosfierro/optimize-featurefrom
leonard/kil-414-refactor-use-asyncio-detailed-and-check-error-response

Conversation

@leonardmq
Copy link
Collaborator

@leonardmq leonardmq commented Feb 17, 2026

What does this PR do?

Changes:

  • refactor: prompt optimization endpoints -> use asyncio_detailed and check_error_response everywhere
  • refactor: allow 2xx, not just 200, in check_error_response
  • refactor: add higher-level response unwrap utils that handle the boilerplate we do everywhere at call site (check type is not HTTPValidationError, check parsed is not None, etc.)
  • refactor: make everywhere we used check_error_response use the new util

Checklists

  • Tests have been run locally and passed
  • New tests have been added to any work in /lib

Summary by CodeRabbit

  • Refactor

    • Streamlined error handling across API endpoints for improved consistency and maintainability.
  • Tests

    • Updated tests to align with refactored error handling approach.

@leonardmq leonardmq requested review from scosman and sfierro February 17, 2026 07:18
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 17, 2026

Walkthrough

This pull request introduces a centralized unwrap_response utility to replace scattered error handling patterns across API endpoints. Multiple API modules are refactored to use this new utility for consistent response validation and error messaging instead of manually checking for HTTPValidationError and parsing responses individually.

Changes

Cohort / File(s) Summary
Response Utilities
app/desktop/studio_server/utils/response_utils.py, app/desktop/studio_server/utils/test_response_utils.py
New module introducing unwrap_response, unwrap_response_allow_none, and check_response_error functions for centralized API response handling and error messaging. Comprehensive test coverage added.
Copilot API Handlers
app/desktop/studio_server/copilot_api.py, app/desktop/studio_server/utils/copilot_utils.py
Replaced explicit HTTPValidationError checks and manual error handling with unwrap_response utility; removed direct imports of HTTPValidationError; simplified control flow across clarify_spec, refine_spec, generate_batch, and other endpoints.
Prompt Optimization API
app/desktop/studio_server/prompt_optimization_job_api.py
Refactored to use unwrap_response for detailed API call responses; removed explicit HTTPValidationError branches and consolidated error handling for get_prompt_optimization_job_result, get_job_status, and check_model_supported endpoints.
Settings API
app/desktop/studio_server/settings_api.py
Simplified entitlements check logic by replacing manual error signaling and None handling with single unwrap_response call.
Prompt Optimization Tests
app/desktop/studio_server/test_prompt_optimization_job_api.py
Updated all AsyncMock targets to detailed API variants; adjusted mocked responses to use helper function; updated assertions to reflect new status codes and error expectations; removed HTTPValidationError imports.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • sfierro

Poem

🐰 Errors once scattered, now gathered with care,
In unwrap_response, a utility so fair,
No more manual checks, no more branches spread,
One path handles them all—validation is fed.
HTTPValidationError bids its farewell,
As centralized handling weaves its spell.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 17.24% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main refactoring work: introducing and using a response unwrap utility across the codebase.
Description check ✅ Passed The description covers the main changes and objectives but is missing required template sections like 'Related Issues' and an unchecked CLA confirmation.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch leonard/kil-414-refactor-use-asyncio-detailed-and-check-error-response

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 and usage tips.

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @leonardmq, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly refactors how API responses are handled throughout the application. By introducing a dedicated response_utils module, it centralizes common logic for checking HTTP status codes, parsing responses, and raising appropriate exceptions. This change streamlines error handling, reduces redundant code at call sites, and enhances the maintainability and consistency of API interactions across various modules.

Highlights

  • New Response Unwrapping Utilities: Introduced new utility functions (unwrap_response, unwrap_response_allow_none) in response_utils.py to centralize and simplify API response handling, including error checking and parsing.
  • Refactored API Endpoints: Refactored existing API endpoints across copilot_api.py, prompt_optimization_job_api.py, and settings_api.py to utilize the new unwrap_response utility, reducing boilerplate code and improving consistency.
  • Enhanced Error Response Handling: Updated the check_response_error logic to correctly handle all 2xx HTTP status codes as successful responses, improving robustness and flexibility.
  • Migration to asyncio_detailed: Migrated API calls from asyncio to asyncio_detailed methods in prompt_optimization_job_api.py and its corresponding test file, ensuring more comprehensive response objects are received.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • app/desktop/studio_server/copilot_api.py
    • Removed direct import of HTTPValidationError.
    • Replaced check_response_error import with unwrap_response import.
    • Updated API call sites to use unwrap_response for simplified error and response parsing.
  • app/desktop/studio_server/prompt_optimization_job_api.py
    • Removed direct import of HTTPValidationError.
    • Replaced check_response_error import with unwrap_response import.
    • Migrated API calls from asyncio to asyncio_detailed methods.
    • Replaced manual error checking and response parsing with unwrap_response calls.
  • app/desktop/studio_server/settings_api.py
    • Removed check_response_error import.
    • Added unwrap_response import.
    • Replaced manual error checking and response parsing with unwrap_response calls.
  • app/desktop/studio_server/test_prompt_optimization_job_api.py
    • Removed direct import of HTTPValidationError.
    • Updated mock API calls from asyncio to asyncio_detailed.
    • Adjusted mock return values to use _make_sdk_response for detailed responses.
    • Modified assertions for status codes and error messages to align with the new unwrap_response behavior.
  • app/desktop/studio_server/utils/copilot_utils.py
    • Removed json, HTTPValidationError, and Response imports.
    • Added unwrap_response import.
    • Removed the check_response_error function.
    • Replaced manual error checking and response parsing with unwrap_response calls.
  • app/desktop/studio_server/utils/response_utils.py
    • Added new file containing check_response_error, unwrap_response_allow_none, and unwrap_response utility functions.
    • Updated check_response_error to accept all 2xx status codes as successful.
  • app/desktop/studio_server/utils/test_response_utils.py
    • Added new file containing comprehensive unit tests for the response_utils module.
Activity
  • No specific activity (comments, reviews, or progress updates) has been recorded for this pull request yet.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@github-actions
Copy link

📊 Coverage Report

Overall Coverage: 91%

Diff: origin/sfierro/optimize-feature...HEAD

  • app/desktop/studio_server/copilot_api.py (66.7%): Missing lines 209,235
  • app/desktop/studio_server/prompt_optimization_job_api.py (100%)
  • app/desktop/studio_server/settings_api.py (100%)
  • app/desktop/studio_server/utils/copilot_utils.py (50.0%): Missing lines 94
  • app/desktop/studio_server/utils/response_utils.py (100%)

Summary

  • Total: 53 lines
  • Missing: 3 lines
  • Coverage: 94%

Line-by-line

View line-by-line diff coverage

app/desktop/studio_server/copilot_api.py

Lines 205-213

  205                 client=client,
  206                 body=questioner_input,
  207             )
  208         )
! 209         result = unwrap_response(
  210             detailed_result,
  211             none_detail="Failed to generate clarifying questions for spec. Please try again.",
  212         )

Lines 231-239

  231         detailed_result = await refine_spec_with_answers_v1_copilot_refine_spec_with_answers_post.asyncio_detailed(
  232             client=client,
  233             body=submit_input,
  234         )
! 235         result = unwrap_response(
  236             detailed_result,
  237             none_detail="Failed to refine spec with question answers. Please try again.",
  238         )

app/desktop/studio_server/utils/copilot_utils.py

Lines 90-98

  90             client=client,
  91             body=generate_input,
  92         )
  93     )
! 94     result = unwrap_response(
  95         detailed_result,
  96         none_detail="Failed to generate synthetic data for spec. Please try again.",
  97     )


Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
app/desktop/studio_server/utils/response_utils.py (1)

46-49: RuntimeError vs HTTPException inconsistency for the HTTPValidationError guard.

This branch raises RuntimeError while every other error path in this module raises HTTPException. If this ever fires in production (e.g., due to an SDK codegen quirk), the caller won't get a clean JSON error — FastAPI will produce a generic 500 with "Internal Server Error" text instead of the structured {"detail": ...} format the rest of the codebase relies on.

Since you already acknowledge this "should never happen," switching to HTTPException keeps the contract uniform at minimal cost.

Proposed fix
     if isinstance(parsed_response, HTTPValidationError):
-        raise RuntimeError("An unknown error occurred.")
+        raise HTTPException(status_code=500, detail="An unknown error occurred.")
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/desktop/studio_server/utils/response_utils.py` around lines 46 - 49, The
guard that currently raises RuntimeError when parsed_response is an instance of
HTTPValidationError should instead raise an HTTPException to keep error
responses consistent; in the function that contains parsed_response and the
HTTPValidationError check (and near check_response_error), replace the
RuntimeError raise with raising fastapi.HTTPException(status_code=400,
detail=...) or another suitable status and include a descriptive detail string
(e.g., "Validation error") so the caller receives the same structured JSON error
format as other branches.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@app/desktop/studio_server/utils/response_utils.py`:
- Around line 46-49: The guard that currently raises RuntimeError when
parsed_response is an instance of HTTPValidationError should instead raise an
HTTPException to keep error responses consistent; in the function that contains
parsed_response and the HTTPValidationError check (and near
check_response_error), replace the RuntimeError raise with raising
fastapi.HTTPException(status_code=400, detail=...) or another suitable status
and include a descriptive detail string (e.g., "Validation error") so the caller
receives the same structured JSON error format as other branches.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a new unwrap_response utility to centralize and simplify API response handling, significantly reducing boilerplate code. A critical security concern was identified regarding sensitive information exposure in the error handling logic of the prompt optimization job API, where internal exception messages are returned directly to the user. It is crucial to use generic error messages for user-facing responses and log detailed exceptions internally to prevent leakage of sensitive system details. Additionally, ensure specific error messages for None responses are preserved by passing the none_detail argument to unwrap_response where appropriate, to maintain the quality of error reporting.

@leonardmq leonardmq merged commit ff6c50e into sfierro/optimize-feature Feb 17, 2026
10 checks passed
@leonardmq leonardmq deleted the leonard/kil-414-refactor-use-asyncio-detailed-and-check-error-response branch February 17, 2026 08:46
Sign up for free to 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.

2 participants