diff --git a/src/smarttools/ui_urwid.py b/src/smarttools/ui_urwid.py index 7f44ed1..728dcbe 100644 --- a/src/smarttools/ui_urwid.py +++ b/src/smarttools/ui_urwid.py @@ -1486,40 +1486,53 @@ class SmartToolsUI: 'button', 'button_focus' ) - adjust_instruction = urwid.Edit(('label', ""), "") + # Default prompt template for AI code generation/adjustment + default_ai_prompt = f"""Modify or generate Python code according to my instruction below. - def on_auto_adjust(_): - instruction = adjust_instruction.edit_text.strip() - if not instruction: - status_text.set_text(('error', "Enter an instruction for the AI")) - return - - current_code = code_edit.edit_text.strip() - if not current_code: - status_text.set_text(('error', "No code to adjust")) - return - - provider_name = selected_ai_provider[0] - status_text.set_text(('label', f"Calling {provider_name}...")) - self.refresh() - - prompt = f"""Modify the following Python code according to this instruction: - -INSTRUCTION: {instruction} +INSTRUCTION: [Describe what you want] CURRENT CODE: ```python -{current_code} +{{code}} ``` AVAILABLE VARIABLES: {', '.join(vars_available)} -Return ONLY the modified Python code, no explanations or markdown fencing.""" +Return ONLY the Python code, no explanations or markdown fencing.""" + + # Multiline editable prompt for AI + ai_prompt_edit = TabPassEdit(edit_text=default_ai_prompt, multiline=True) + ai_prompt_styled = urwid.AttrMap(ai_prompt_edit, 'edit', 'edit_focus') + ai_prompt_walker = urwid.SimpleFocusListWalker([ai_prompt_styled]) + ai_prompt_listbox = urwid.ListBox(ai_prompt_walker) + ai_prompt_box = urwid.LineBox(ai_prompt_listbox, title="Prompt") + + # Output/feedback area for AI responses + ai_output_text = urwid.Text("") + ai_output_walker = urwid.SimpleFocusListWalker([ai_output_text]) + ai_output_listbox = urwid.ListBox(ai_output_walker) + ai_output_box = urwid.LineBox(ai_output_listbox, title="Output & Feedback") + + def on_auto_adjust(_): + prompt_template = ai_prompt_edit.edit_text.strip() + if not prompt_template: + ai_output_text.set_text(('error', "Enter a prompt for the AI")) + return + + current_code = code_edit.edit_text.strip() + + # Replace {code} placeholder with actual code + prompt = prompt_template.replace("{code}", current_code) + + provider_name = selected_ai_provider[0] + ai_output_text.set_text(('label', f"Calling {provider_name}...\nPlease wait...")) + self.refresh() result = call_provider(provider_name, prompt) if result.success: new_code = result.text.strip() + # Strip markdown code fences if present if new_code.startswith("```python"): new_code = new_code[9:] if new_code.startswith("```"): @@ -1529,14 +1542,31 @@ Return ONLY the modified Python code, no explanations or markdown fencing.""" new_code = new_code.strip() code_edit.set_edit_text(new_code) - status_text.set_text(('success', "Code updated by AI")) + ai_output_text.set_text(('success', f"✓ Code updated successfully!\n\nProvider: {provider_name}\nResponse length: {len(result.text)} chars")) else: - status_text.set_text(('error', f"AI error: {result.error[:50]}")) + error_msg = result.error or "Unknown error" + ai_output_text.set_text(('error', f"✗ Error from {provider_name}:\n\n{error_msg}")) auto_adjust_btn = urwid.AttrMap( urwid.Button("Auto-adjust", on_auto_adjust), 'button', 'button_focus' ) + + # Build the AI assist box with provider selector, prompt editor, output area, and button + ai_provider_row = urwid.Columns([ + ('pack', urwid.Text(('label', "Provider: "))), + ('pack', ai_provider_btn), + ('pack', ai_provider_select_btn), + ]) + + ai_assist_content = urwid.Pile([ + ('pack', ai_provider_row), + ('pack', urwid.Divider()), + ('weight', 2, ai_prompt_box), + ('weight', 1, ai_output_box), + ('pack', urwid.Padding(auto_adjust_btn, align='center', width=16)), + ]) + ai_assist_box = urwid.LineBox(ai_assist_content, title="AI Assisted Auto-adjust") # --- End Auto-adjust feature --- def do_load(): @@ -1624,15 +1654,11 @@ Return ONLY the modified Python code, no explanations or markdown fencing.""" code_scrollbar = DOSScrollBar(code_listbox) code_box = urwid.LineBox(code_scrollbar, title="Code") - # Auto-adjust row - auto_adjust_row = urwid.Columns([ - ('pack', ai_provider_btn), - ('pack', ai_provider_select_btn), - ('pack', urwid.Text(" ")), - ('weight', 1, urwid.AttrMap(adjust_instruction, 'edit', 'edit_focus')), - ('pack', urwid.Text(" ")), - ('pack', auto_adjust_btn), - ]) + # Layout: Code editor on left, AI assist box on right + main_columns = urwid.Columns([ + ('weight', 1, code_box), + ('weight', 1, ai_assist_box), + ], dividechars=1) # Use TabCyclePile so Tab cycles between sections # Note: All flow widgets must be explicitly wrapped in ('pack', ...) when @@ -1646,16 +1672,14 @@ Return ONLY the modified Python code, no explanations or markdown fencing.""" ('pack', load_btn), ])), ('pack', status_text), - ('weight', 1, code_box), - ('pack', urwid.Divider()), - ('pack', auto_adjust_row), + ('weight', 1, main_columns), ('pack', urwid.Divider()), ('pack', urwid.AttrMap(output_edit, 'edit', 'edit_focus')), - ], tab_positions=[2, 4, 6, 8]) + ], tab_positions=[2, 4, 6]) title = "Edit Code Step" if existing else "Add Code Step" dialog = Dialog(title, body, [("OK", on_ok), ("Cancel", on_cancel)]) - self.show_overlay(dialog, width=70, height=24) + self.show_overlay(dialog, width=90, height=30) def _on_save_tool(self, _): """Save the tool."""