Spaces:
Sleeping
Sleeping
| """ | |
| ui/components.py | |
| ---------------- | |
| Reusable Gradio component builders for AutoDevAgent. | |
| Each function returns a configured Gradio component (or group of | |
| components) that can be assembled into the main app.py layout. | |
| Components built here: | |
| - build_hitl_panel() Human-in-the-Loop panel β shown when max | |
| retries is hit. Displays the failed code, | |
| the last error, 2-3 fix options, and an | |
| inline code editor. | |
| - build_reflection_panel() Self-reflection display β shows the | |
| debug agent's structured reasoning per | |
| iteration ("saw X, thought Y, did Z"). | |
| - build_iteration_counter() Live iteration + token + time display. | |
| - build_model_switcher() Toggle between Llama 8B and 70B. | |
| - build_language_selector() Language radio with auto-detect badge. | |
| Design: | |
| - All components are built with Gradio's Blocks API. | |
| - State is managed via gr.State objects passed through event handlers. | |
| - Components are returned as named dicts so app.py can wire them | |
| into event handlers without importing internals. | |
| Usage: | |
| import gradio as gr | |
| from ui.components import build_hitl_panel, build_reflection_panel | |
| with gr.Blocks() as demo: | |
| hitl = build_hitl_panel() | |
| reflex = build_reflection_panel() | |
| """ | |
| import gradio as gr | |
| from typing import Any | |
| # ------------------------------------------------------------------ # | |
| # Human-in-the-Loop Panel # | |
| # ------------------------------------------------------------------ # | |
| def build_hitl_panel() -> dict[str, Any]: | |
| """ | |
| Build the Human-in-the-Loop panel shown when max retries is hit. | |
| Layout: | |
| ββββββββββββββββββββββββββββββββββββββββββ | |
| β β Max retries reached β | |
| β Last error: <error text> β | |
| β β | |
| β Fix options: β | |
| β β Option 1 description β | |
| β β Option 2 description β | |
| β β Option 3 description β | |
| β β | |
| β Or edit the code directly: β | |
| β [code editor textbox] β | |
| β β | |
| β [Apply fix] [Resubmit edited code] β | |
| ββββββββββββββββββββββββββββββββββββββββββ | |
| Returns: | |
| Dict with keys: | |
| - "panel": gr.Group β the whole panel | |
| - "error_display": gr.Textbox β shows the last error | |
| - "options_radio": gr.Radio β 2-3 fix options | |
| - "code_editor": gr.Code β inline code editor | |
| - "apply_btn": gr.Button β apply chosen fix option | |
| - "resubmit_btn": gr.Button β resubmit edited code | |
| """ | |
| with gr.Group(visible=False) as panel: | |
| gr.Markdown("### β Max retries reached β Human input needed") | |
| with gr.Row(): | |
| gr.Markdown( | |
| "The agent could not fix the code automatically. " | |
| "Choose a fix strategy or edit the code directly below." | |
| ) | |
| error_display = gr.Textbox( | |
| label="Last error", | |
| lines=4, | |
| interactive=False, | |
| elem_id="hitl_error_display", | |
| ) | |
| options_radio = gr.Radio( | |
| choices=[], | |
| label="Suggested fix strategies", | |
| value=None, | |
| elem_id="hitl_options_radio", | |
| ) | |
| gr.Markdown("**Or edit the code directly:**") | |
| code_editor = gr.Code( | |
| label="Code editor", | |
| language="python", | |
| lines=20, | |
| interactive=True, | |
| elem_id="hitl_code_editor", | |
| ) | |
| with gr.Row(): | |
| apply_btn = gr.Button( | |
| value="Apply selected fix", | |
| variant="primary", | |
| size="sm", | |
| ) | |
| resubmit_btn = gr.Button( | |
| value="Resubmit edited code", | |
| variant="secondary", | |
| size="sm", | |
| ) | |
| return { | |
| "panel": panel, | |
| "error_display": error_display, | |
| "options_radio": options_radio, | |
| "code_editor": code_editor, | |
| "apply_btn": apply_btn, | |
| "resubmit_btn": resubmit_btn, | |
| } | |
| def update_hitl_panel( | |
| hitl_components: dict[str, Any], | |
| error_msg: str, | |
| options: list[str], | |
| broken_code: str, | |
| ) -> None: | |
| """ | |
| Populate the HITL panel with the current error state. | |
| Called from app.py when the pipeline returns AWAITING_HUMAN status. | |
| Updates the error display, radio options, and code editor in place. | |
| Args: | |
| hitl_components: Dict returned by build_hitl_panel(). | |
| error_msg: The last error message from the executor. | |
| options: List of 2-3 fix option strings from DebugAgent. | |
| broken_code: The most recent failing code to pre-populate | |
| the inline editor. | |
| """ | |
| hitl_components["error_display"].value = error_msg | |
| hitl_components["options_radio"].choices = options | |
| hitl_components["options_radio"].value = None | |
| hitl_components["code_editor"].value = broken_code | |
| hitl_components["panel"].visible = True | |
| # ------------------------------------------------------------------ # | |
| # Clarification Panel # | |
| # ------------------------------------------------------------------ # | |
| def build_clarification_panel() -> dict[str, Any]: | |
| """ | |
| Build the clarification panel shown when the agent needs more info. | |
| Layout: | |
| ββββββββββββββββββββββββββββββββββββββββββ | |
| β π€ Task needs clarification β | |
| β <agent's question> β | |
| β [user input textbox] β | |
| β [Submit Clarification] β | |
| ββββββββββββββββββββββββββββββββββββββββββ | |
| Returns: | |
| Dict with keys: | |
| - "panel": gr.Group β container (visible=False by default) | |
| - "question_md": gr.Markdown β displays the agent's question | |
| - "answer_input": gr.Textbox β user types their clarification | |
| - "submit_btn": gr.Button β submits the clarification | |
| """ | |
| with gr.Group(visible=False, elem_id="clarification_panel") as panel: | |
| gr.Markdown("### π€ Task needs clarification") | |
| question_md = gr.Markdown( | |
| value="", | |
| elem_id="clarification_question", | |
| ) | |
| answer_input = gr.Textbox( | |
| label="Your clarification", | |
| placeholder="Type your answer here...", | |
| lines=2, | |
| elem_id="clarification_answer", | |
| ) | |
| with gr.Row(): | |
| submit_btn = gr.Button( | |
| value="Submit Clarification βΆ", | |
| variant="primary", | |
| size="sm", | |
| elem_id="clarification_submit_btn", | |
| ) | |
| return { | |
| "panel": panel, | |
| "question_md": question_md, | |
| "answer_input": answer_input, | |
| "submit_btn": submit_btn, | |
| } | |
| # ------------------------------------------------------------------ # | |
| # Self-Reflection Panel # | |
| # ------------------------------------------------------------------ # | |
| def build_reflection_panel() -> dict[str, Any]: | |
| """ | |
| Build the self-reflection panel displayed during each debug iteration. | |
| Shows the debug agent's structured reasoning before each rewrite: | |
| - What I saw: the exact error observed | |
| - What I think: the agent's hypothesis for the root cause | |
| - What I will do: the specific change the agent will make | |
| Returns: | |
| Dict with keys: | |
| - "panel": gr.Accordion β collapsible wrapper | |
| - "saw_box": gr.Textbox β what the agent observed | |
| - "think_box": gr.Textbox β the agent's hypothesis | |
| - "do_box": gr.Textbox β the planned fix | |
| - "iteration_md": gr.Markdown β current iteration label | |
| """ | |
| with gr.Accordion( | |
| label="Self-reflection (debug agent reasoning)", | |
| open=False, | |
| visible=False, | |
| ) as panel: | |
| iteration_md = gr.Markdown("**Iteration:** β") | |
| with gr.Row(): | |
| saw_box = gr.Textbox( | |
| label="What I saw", | |
| lines=2, | |
| interactive=False, | |
| elem_id="reflection_saw", | |
| ) | |
| with gr.Row(): | |
| think_box = gr.Textbox( | |
| label="What I think caused it", | |
| lines=2, | |
| interactive=False, | |
| elem_id="reflection_think", | |
| ) | |
| with gr.Row(): | |
| do_box = gr.Textbox( | |
| label="What I will change", | |
| lines=2, | |
| interactive=False, | |
| elem_id="reflection_do", | |
| ) | |
| return { | |
| "panel": panel, | |
| "saw_box": saw_box, | |
| "think_box": think_box, | |
| "do_box": do_box, | |
| "iteration_md": iteration_md, | |
| } | |
| def update_reflection_panel( | |
| reflection_components: dict[str, Any], | |
| what_i_saw: str, | |
| what_i_think: str, | |
| what_i_will_do: str, | |
| iteration: int, | |
| max_retries: int, | |
| ) -> None: | |
| """ | |
| Populate the reflection panel with the latest debug iteration data. | |
| Args: | |
| reflection_components: Dict returned by build_reflection_panel(). | |
| what_i_saw: The error or wrong output observed. | |
| what_i_think: The agent's hypothesis. | |
| what_i_will_do: The planned fix. | |
| iteration: Current iteration number (1-based). | |
| max_retries: Configured max retries for the label. | |
| """ | |
| reflection_components["iteration_md"].value = ( | |
| f"**Iteration:** {iteration} / {max_retries}" | |
| ) | |
| reflection_components["saw_box"].value = what_i_saw | |
| reflection_components["think_box"].value = what_i_think | |
| reflection_components["do_box"].value = what_i_will_do | |
| reflection_components["panel"].visible = True | |
| reflection_components["panel"].open = True | |
| # ------------------------------------------------------------------ # | |
| # Iteration Counter + Observability Strip # | |
| # ------------------------------------------------------------------ # | |
| def build_stats_strip() -> dict[str, Any]: | |
| """ | |
| Build the live stats strip showing iteration count, exec time, | |
| and Groq token usage. | |
| Displayed as a compact row of metric cards beneath the main output. | |
| Returns: | |
| Dict with keys: | |
| - "iterations_md": gr.Markdown β debug iteration count | |
| - "exec_time_md": gr.Markdown β execution time in seconds | |
| - "tokens_md": gr.Markdown β total Groq tokens used | |
| - "warning_md": gr.Markdown β rate limit warning (hidden by default) | |
| """ | |
| with gr.Row(elem_id="stats_strip"): | |
| iterations_md = gr.Markdown( | |
| value="**Iterations:** 0", | |
| elem_id="stats_iterations", | |
| ) | |
| exec_time_md = gr.Markdown( | |
| value="**Time:** 0.0s", | |
| elem_id="stats_exec_time", | |
| ) | |
| tokens_md = gr.Markdown( | |
| value="**Tokens:** 0", | |
| elem_id="stats_tokens", | |
| ) | |
| warning_md = gr.Markdown( | |
| value="", | |
| visible=False, | |
| elem_id="stats_warning", | |
| ) | |
| return { | |
| "iterations_md": iterations_md, | |
| "exec_time_md": exec_time_md, | |
| "tokens_md": tokens_md, | |
| "warning_md": warning_md, | |
| } | |
| def update_stats_strip( | |
| stats_components: dict[str, Any], | |
| iterations: int, | |
| exec_time: float, | |
| total_tokens: int, | |
| rate_limit_warning: bool = False, | |
| ) -> None: | |
| """ | |
| Update the stats strip with current pipeline run metrics. | |
| Args: | |
| stats_components: Dict returned by build_stats_strip(). | |
| iterations: Number of debug iterations completed. | |
| exec_time: Total wall-clock time in seconds. | |
| total_tokens: Total Groq tokens used this run. | |
| rate_limit_warning: If True, show a rate limit warning. | |
| """ | |
| stats_components["iterations_md"].value = f"**Iterations:** {iterations}" | |
| stats_components["exec_time_md"].value = f"**Time:** {exec_time:.1f}s" | |
| stats_components["tokens_md"].value = f"**Tokens:** {total_tokens:,}" | |
| if rate_limit_warning: | |
| stats_components["warning_md"].value = ( | |
| "β Approaching Groq rate limit β consider switching to llama3-8b" | |
| ) | |
| stats_components["warning_md"].visible = True | |
| else: | |
| stats_components["warning_md"].visible = False | |
| # ------------------------------------------------------------------ # | |
| # Model Switcher # | |
| # ------------------------------------------------------------------ # | |
| def build_model_switcher() -> dict[str, Any]: | |
| """ | |
| Build the model switcher toggle between Llama 3.1 8B and 70B. | |
| 8B is faster and cheaper β good for simple tasks and when | |
| approaching rate limits. 70B gives higher quality for complex tasks. | |
| Returns: | |
| Dict with keys: | |
| - "radio": gr.Radio β model selection | |
| """ | |
| radio = gr.Radio( | |
| choices=["llama3-8b-8192", "llama3-70b-8192"], | |
| value="llama3-70b-8192", | |
| label="Model", | |
| info="8B is faster Β· 70B is more capable", | |
| elem_id="model_switcher", | |
| ) | |
| return {"radio": radio} | |
| # ------------------------------------------------------------------ # | |
| # Language Selector with Auto-detect Badge # | |
| # ------------------------------------------------------------------ # | |
| def build_language_selector() -> dict[str, Any]: | |
| """ | |
| Build the language selector radio with auto-detect status display. | |
| The auto-detect badge shows the detected language and confidence | |
| so the user knows whether to trust the pre-selection. | |
| Returns: | |
| Dict with keys: | |
| - "radio": gr.Radio β Python / SQL selector | |
| - "badge_md": gr.Markdown β auto-detect result badge | |
| """ | |
| with gr.Group(): | |
| radio = gr.Radio( | |
| choices=["python", "sql"], | |
| value="python", | |
| label="Language", | |
| elem_id="language_selector", | |
| ) | |
| badge_md = gr.Markdown( | |
| value="", | |
| visible=False, | |
| elem_id="language_badge", | |
| ) | |
| return { | |
| "radio": radio, | |
| "badge_md": badge_md, | |
| } | |
| def update_language_badge( | |
| selector_components: dict[str, Any], | |
| detected_language: str, | |
| confidence: str, | |
| reason: str, | |
| ) -> None: | |
| """ | |
| Update the auto-detect badge after detection runs. | |
| Args: | |
| selector_components: Dict returned by build_language_selector(). | |
| detected_language: The detected language string. | |
| confidence: 'high', 'medium', or 'low'. | |
| reason: One-sentence explanation of the detection. | |
| """ | |
| emoji = {"high": "π’", "medium": "π‘", "low": "π΄"}.get(confidence, "βͺ") | |
| selector_components["badge_md"].value = ( | |
| f"{emoji} Auto-detected: **{detected_language}** " | |
| f"({confidence} confidence) β {reason}" | |
| ) | |
| selector_components["badge_md"].visible = True | |
| selector_components["radio"].value = detected_language | |