# ============================================================================ # CENTRALIZED APPLICATION CONFIGURATION (FULL INTEGRATED) # ============================================================================ # Drop-in config used by app_gradio.py and other modules. # This file is resilient: prefers values from graph_config.py when available, # but falls back to safe defaults to avoid runtime AttributeError. # ============================================================================ import os import json import logging from typing import Dict, Any, List, Optional # Safe import of gradio (UI helpers) try: import gradio as gr except Exception: gr = None # Initialize module logger log = logging.getLogger("app_config") if not log.handlers: # Basic console logging if not configured elsewhere h = logging.StreamHandler() fmt = logging.Formatter("%(asctime)s - %(levelname)s - %(name)s - %(message)s") h.setFormatter(fmt) log.addHandler(h) log.setLevel(logging.INFO) # ============================================================================ # Attempt to import graph_config for canonical values; if absent, use defaults # ============================================================================ try: import graph_config as graph_cfg # type: ignore except Exception: graph_cfg = None def _from_graph(attr: str, default): """Helper to return attr from graph_cfg if available, else default.""" try: if graph_cfg is not None and hasattr(graph_cfg, attr): return getattr(graph_cfg, attr) except Exception: pass return default # ============================================================================ # FILES & PATHS # ============================================================================ OUT_DIR = _from_graph("OUT_DIR", os.environ.get("OUT_DIR", "outputs")) OUTPUTS_DIR = _from_graph("OUTPUTS_DIR", "outputs") UPLOADS_DIR = _from_graph("UPLOADS_DIR", "uploads") USER_ARTIFACTS_DIR = _from_graph("USER_ARTIFACTS_DIR", "outputs/user_artifacts") EXPORTS_DIR = _from_graph("EXPORTS_DIR", os.path.join(OUT_DIR, "exports")) FEEDBACK_STORAGE_DIR = _from_graph("FEEDBACK_STORAGE_DIR", os.path.join(OUTPUTS_DIR, "feedback")) ARTIFACT_REGISTRY_FILE = _from_graph("ARTIFACT_REGISTRY_FILE", os.path.join(OUTPUTS_DIR, "artifact_registry.json")) # Directory creation flag used by os.makedirs(..., exist_ok=...) DIR_EXIST_OK = _from_graph("DIR_EXIST_OK", True) # Ensure core directories exist early os.makedirs(OUT_DIR, exist_ok=DIR_EXIST_OK) os.makedirs(OUTPUTS_DIR, exist_ok=DIR_EXIST_OK) os.makedirs(UPLOADS_DIR, exist_ok=DIR_EXIST_OK) os.makedirs(USER_ARTIFACTS_DIR, exist_ok=DIR_EXIST_OK) os.makedirs(os.path.dirname(ARTIFACT_REGISTRY_FILE), exist_ok=DIR_EXIST_OK) os.makedirs(FEEDBACK_STORAGE_DIR, exist_ok=DIR_EXIST_OK) # ============================================================================ # THEME & UI METADATA # ============================================================================ GRADIO_THEME = _from_graph("GRADIO_THEME", "soft") def get_theme(): """Return a gradio theme object or None if gr is not available.""" if gr is None: return None theme_map = { "default": gr.themes.Default(), "soft": gr.themes.Soft(), "monochrome": gr.themes.Monochrome(), "glass": gr.themes.Glass() } return theme_map.get(GRADIO_THEME, gr.themes.Soft()) APP_TITLE = _from_graph("APP_TITLE", "Autonomous AI Lab") APP_TITLE_EMOJI = _from_graph("APP_TITLE_EMOJI", "πŸ€–") APP_SUBTITLE = _from_graph("APP_SUBTITLE", "*AI-powered research and development assistant*") CUSTOM_CSS = _from_graph("CUSTOM_CSS", """ /* Basic layout helpers */ .status-bar { padding: 8px 12px; background: #f8f9fa; border-radius: 6px; font-size: 0.95em; margin: 8px 0; } .artifact-list { font-size: 0.9em; max-height: 220px; overflow-y: auto; } .context-indicator { font-size: 0.9em; color: #444; margin-top: 6px; } .warning-text { font-size: 0.85em; color: #666; font-style: italic; } @media (max-width: 768px) { .gradio-container { padding: 8px !important; } .chatbot { height: 60vh !important; } } """) # ============================================================================ # CONTEXT INDICATORS # ============================================================================ SHOW_CONTEXT_INDICATOR = _from_graph("SHOW_CONTEXT_INDICATOR", True) CONTEXT_INDICATOR_NEW = _from_graph("CONTEXT_INDICATOR_NEW", "πŸ“Š **New conversation**") CONTEXT_INDICATOR_FOLLOW_UP = _from_graph("CONTEXT_INDICATOR_FOLLOW_UP", "πŸ”„ Follow-up detected") CONTEXT_INDICATOR_FORMAT = _from_graph("CONTEXT_INDICATOR_FORMAT", "πŸ’¬ **Context: {count} exchange(s)**") # ============================================================================ # DEFAULT CONFIG & HELPERS (used by app_gradio.get_default_state) # ============================================================================ DEFAULT_REWORK_CYCLES = _from_graph("DEFAULT_REWORK_CYCLES", 0) DEFAULT_APPROVED = _from_graph("DEFAULT_APPROVED", False) DEFAULT_BUDGET_EXCEEDED = _from_graph("DEFAULT_BUDGET_EXCEEDED", False) DEFAULT_USER_CONFIRMED_APPROVE_WITH_WARNING = _from_graph("DEFAULT_USER_CONFIRMED_APPROVE_WITH_WARNING", False) DEFAULT_AWAITING_USER_CONFIRMATION = _from_graph("DEFAULT_AWAITING_USER_CONFIRMATION", False) DEFAULT_CONFIG = _from_graph("DEFAULT_CONFIG", { # Execution control & loops "max_loops": _from_graph("DEFAULT_MAX_LOOPS", 3), "rework_cycles": DEFAULT_REWORK_CYCLES, # Budget & cost "budget": _from_graph("DEFAULT_INITIAL_BUDGET", 0.10), "current_cost": _from_graph("DEFAULT_INITIAL_COST", 0.0), "stop_threshold": _from_graph("DEFAULT_STOP_THRESHOLD", 1.2), "budget_buffer_percentage": _from_graph("BUDGET_BUFFER_PERCENTAGE", 0.20), # Governance "flexible_budget_mode": _from_graph("DEFAULT_FLEXIBLE_BUDGET_MODE", True), "auto_accept_approved_with_warning": _from_graph("DEFAULT_AUTO_ACCEPT_APPROVED_WITH_WARNING", True), "allow_escalation": _from_graph("DEFAULT_ALLOW_ESCALATION", False), "preferred_tier": _from_graph("DEFAULT_PREFERRED_TIER", "standard"), # Booleans "approved": DEFAULT_APPROVED, "budget_exceeded": DEFAULT_BUDGET_EXCEEDED, "user_confirmed_approve_with_warning": DEFAULT_USER_CONFIRMED_APPROVE_WITH_WARNING, "awaiting_user_confirmation": DEFAULT_AWAITING_USER_CONFIRMATION, }) def get_default_config() -> Dict[str, Any]: """Return a shallow copy of DEFAULT_CONFIG so callers can mutate safely.""" return DEFAULT_CONFIG.copy() # ============================================================================ # GRADIO UI CONSTANTS (used by app_gradio) # ============================================================================ # Chat layout CHAT_COLUMN_SCALE = _from_graph("CHAT_COLUMN_SCALE", 3) SIDEBAR_COLUMN_SCALE = _from_graph("SIDEBAR_COLUMN_SCALE", 1) CHATBOT_HEIGHT = _from_graph("CHATBOT_HEIGHT", 520) CHATBOT_SHOW_LABEL = _from_graph("CHATBOT_SHOW_LABEL", False) CHAT_COLUMN_PADDING = _from_graph("CHAT_COLUMN_PADDING", 8) # Placeholder text ASSISTANT_THINKING_PLACEHOLDER = _from_graph("ASSISTANT_THINKING_PLACEHOLDER", "_Thinking..._") PLACEHOLDER_MESSAGE_INPUT = _from_graph("PLACEHOLDER_MESSAGE_INPUT", "Type your request and press Send") # Input box sizing INPUT_TEXTBOX_SCALE = _from_graph("INPUT_TEXTBOX_SCALE", 4) INPUT_LINES = _from_graph("INPUT_LINES", 3) INPUT_SHOW_LABEL = _from_graph("INPUT_SHOW_LABEL", False) # Buttons, sizes and variants BUTTON_SEND = _from_graph("BUTTON_SEND", "Send") BUTTON_PROCEED = _from_graph("BUTTON_PROCEED", "Proceed") BUTTON_CANCEL = _from_graph("BUTTON_CANCEL", "Cancel") BUTTON_NEW_CHAT = _from_graph("BUTTON_NEW_CHAT", "New Chat") BUTTON_RESET = _from_graph("BUTTON_RESET", "Reset System") BUTTON_REFRESH = _from_graph("BUTTON_REFRESH", "Refresh") BUTTON_SIZE_SMALL = _from_graph("BUTTON_SIZE_SMALL", "sm") BUTTON_SIZE_LARGE = _from_graph("BUTTON_SIZE_LARGE", None) BUTTON_VARIANT_PRIMARY = _from_graph("BUTTON_VARIANT_PRIMARY", "primary") BUTTON_VARIANT_SECONDARY = _from_graph("BUTTON_VARIANT_SECONDARY", "secondary") BUTTON_VARIANT_STOP = _from_graph("BUTTON_VARIANT_STOP", "stop") PROCEED_BUTTON_SCALE = _from_graph("PROCEED_BUTTON_SCALE", 1) CANCEL_BUTTON_SCALE = _from_graph("CANCEL_BUTTON_SCALE", 1) SUBMIT_BUTTON_SCALE = _from_graph("SUBMIT_BUTTON_SCALE", 1) PROCEED_BUTTON_SCALE = _from_graph("PROCEED_BUTTON_SCALE", 1) BUTTON_VARIANT_PRIMARY = _from_graph("BUTTON_VARIANT_PRIMARY", "primary") # Approval box behavior APPROVAL_BOX_DEFAULT_VISIBLE = _from_graph("APPROVAL_BOX_DEFAULT_VISIBLE", False) # Budget UI LABEL_MAX_BUDGET = _from_graph("LABEL_MAX_BUDGET", "Max Budget (USD)") BUDGET_DEFAULT_VALUE = _from_graph("BUDGET_DEFAULT_VALUE", 0.10) BUDGET_MINIMUM = _from_graph("BUDGET_MINIMUM", 0.0) BUDGET_STEP = _from_graph("BUDGET_STEP", 0.01) BUDGET_INPUT_SCALE = _from_graph("BUDGET_INPUT_SCALE", 1) LABEL_FLEXIBLE_BUDGET = _from_graph("LABEL_FLEXIBLE_BUDGET", "Flexible Budget") LABEL_PREFERRED_TIER = _from_graph("LABEL_PREFERRED_TIER", "Preferred Tier") TIER_CHOICES = _from_graph("TIER_CHOICES", ["lite", "standard", "full"]) TIER_DEFAULT = _from_graph("TIER_DEFAULT", "standard") # Feedback UI SECTION_FEEDBACK = _from_graph("SECTION_FEEDBACK", "Feedback & Rating") FEEDBACK_PURPOSE_TEXT = _from_graph("FEEDBACK_PURPOSE_TEXT", "Help us improve by rating this run.") FEEDBACK_CATEGORIES = _from_graph("FEEDBACK_CATEGORIES", {"quality": "Quality", "usability": "Usability", "other": "Other"}) LABEL_RATING = _from_graph("LABEL_RATING", "Rating") RATING_MIN = _from_graph("RATING_MIN", 1) RATING_MAX = _from_graph("RATING_MAX", 5) RATING_DEFAULT_VALUE = _from_graph("RATING_DEFAULT_VALUE", 5) LABEL_FEEDBACK_COMMENTS = _from_graph("LABEL_FEEDBACK_COMMENTS", "Comments") FEEDBACK_COMMENT_LINES = _from_graph("FEEDBACK_COMMENT_LINES", 3) FEEDBACK_PLACEHOLDER = _from_graph("FEEDBACK_PLACEHOLDER", "Optional: leave a comment about your experience") BUTTON_SUBMIT_FEEDBACK = _from_graph("BUTTON_SUBMIT_FEEDBACK", "Submit Feedback") FEEDBACK_THANK_YOU_MESSAGES = _from_graph("FEEDBACK_THANK_YOU_MESSAGES", [ "Thanks β€” your feedback helps us improve!", "Appreciate your feedback β€” thank you!", "Thanks! We logged your feedback." ]) # Files UI SECTION_FILES_ARTIFACTS = _from_graph("SECTION_FILES_ARTIFACTS", "Files & Artifacts") LABEL_UPLOAD_FILES = _from_graph("LABEL_UPLOAD_FILES", "Upload files") ALLOWED_FILE_TYPES = _from_graph("ALLOWED_FILE_TYPES", None) # None means allow any UPLOAD_STATUS_SHOW_LABEL = _from_graph("UPLOAD_STATUS_SHOW_LABEL", False) PLACEHOLDER_NO_FILES = _from_graph("PLACEHOLDER_NO_FILES", "No files uploaded") # Debug / JSON display SECTION_DEBUG = _from_graph("SECTION_DEBUG", "Debug") ACCORDION_DEBUG_OPEN = _from_graph("ACCORDION_DEBUG_OPEN", False) LABEL_AGENT_STATE = _from_graph("LABEL_AGENT_STATE", "Agent State (debug)") DEBUG_JSON_VISIBLE = _from_graph("DEBUG_JSON_VISIBLE", False) # ============================================================================ # UI text / status messages (fallbacks) # ============================================================================ RESET_SUCCESS_MESSAGE = _from_graph("RESET_SUCCESS_MESSAGE", "βœ… System reset complete.") RESET_LOG_MESSAGE = _from_graph("RESET_LOG_MESSAGE", RESET_SUCCESS_MESSAGE) RESET_ERROR_MESSAGE_PREFIX = _from_graph("RESET_ERROR_MESSAGE_PREFIX", "⚠️ Reset error: ") NO_FILE_UPLOADED_MESSAGE = _from_graph("NO_FILE_UPLOADED_MESSAGE", "No file uploaded.") FILE_UPLOAD_SUCCESS_PREFIX = _from_graph("FILE_UPLOAD_SUCCESS_PREFIX", "πŸ“Ž Uploaded ") FILE_UPLOAD_SUCCESS_SUFFIX = _from_graph("FILE_UPLOAD_SUCCESS_SUFFIX", " file(s): ") UPLOAD_LOG_MESSAGE_PREFIX = _from_graph("UPLOAD_LOG_MESSAGE_PREFIX", "Uploaded: ") NO_ARTIFACTS_MESSAGE = _from_graph("NO_ARTIFACTS_MESSAGE", "No artifacts yet.") NO_ARTIFACTS_GENERATED_MESSAGE = _from_graph("NO_ARTIFACTS_GENERATED_MESSAGE", "No artifacts generated yet.") CLEAR_CONVERSATION_MESSAGE = _from_graph("CLEAR_CONVERSATION_MESSAGE", "πŸ—‘οΈ Conversation cleared.") ASSISTANT_THINKING_PLACEHOLDER = _from_graph("ASSISTANT_THINKING_PLACEHOLDER", ASSISTANT_THINKING_PLACEHOLDER) # Execution status messages STATUS_ANALYZING = _from_graph("STATUS_ANALYZING", "πŸ”„ Analyzing request...") STATUS_READY = _from_graph("STATUS_READY", "πŸ’¬ Ready") STATUS_AWAITING_APPROVAL = _from_graph("STATUS_AWAITING_APPROVAL", "⏸️ Awaiting approval") STATUS_TASK_APPROVED = _from_graph("STATUS_TASK_APPROVED", "βœ… Task approved. Starting...") STATUS_RUNNING_PREFIX = _from_graph("STATUS_RUNNING_PREFIX", "πŸ”„ ") STATUS_RUNNING_SUFFIX = _from_graph("STATUS_RUNNING_SUFFIX", " | Cost: ${cost:.2f} / ${threshold:.2f} (120%)") STATUS_TASK_COMPLETE = _from_graph("STATUS_TASK_COMPLETE", "βœ… Task complete | Cost: ${cost:.2f} (${budget} + {buffer}% buffer)") STATUS_BUDGET_EXCEEDED = _from_graph("STATUS_BUDGET_EXCEEDED", "⚠️ Budget limit reached | Used: ${cost:.2f} / ${threshold:.2f}") STATUS_PARTIAL_COMPLETION = _from_graph("STATUS_PARTIAL_COMPLETION", "⚠️ Partial completion | Cost: ${cost:.2f}") STATUS_CANCELLED = _from_graph("STATUS_CANCELLED", "⏸️ Cancelled. Ready.") STATUS_NO_RUNTIME = _from_graph("STATUS_NO_RUNTIME", "❌ No runtime") STATUS_ERROR_PREFIX = _from_graph("STATUS_ERROR_PREFIX", "❌ Error: ") ERROR_EXECUTION_PREFIX = _from_graph("ERROR_EXECUTION_PREFIX", "❌ Execution failed: ") # ---------------------------------------------------------------------------- # AVATAR CONFIGURATION β€” minimal, robust, and guaranteed to return >= 2 items # ---------------------------------------------------------------------------- import os from typing import List # Prefer a local avatar placed at ./assets/avatar.png (relative to project root) LOCAL_AVATAR_PATH = os.path.join(os.path.dirname(__file__), "assets", "avatar.png") # Secondary local candidate(s) LOCAL_AVATAR_CANDIDATES = [ LOCAL_AVATAR_PATH, os.path.join(os.path.dirname(__file__), "static", "avatar.png"), os.path.join(os.path.dirname(__file__), "assets", "bot.png"), ] # Stable remote fallbacks (used only if no local file is present) REMOTE_FALLBACKS = [ "https://i.imgur.com/b5OqI32.png", "https://i.imgur.com/8Km9tLL.png" ] def get_avatar_images() -> List[str]: """ Return a list of avatar image paths/URLs with length >= 2. Priority: 1) Use two local images if available 2) If only one local image found, duplicate it (safe) 3) Else return two stable remote fallback URLs """ imgs: List[str] = [] # 1) collect existing local candidates for candidate in LOCAL_AVATAR_CANDIDATES: try: if candidate and os.path.exists(candidate): imgs.append(candidate) except Exception: # ignore filesystem oddities; continue to next candidate continue if len(imgs) >= 2: break # 2) if only one local image found, duplicate it so Gradio has two entries if len(imgs) == 1: imgs.append(imgs[0]) # 3) if none found, use remote fallbacks if not imgs: imgs = REMOTE_FALLBACKS.copy() # 4) final safety: ensure length >= 2 (pad with last element) while len(imgs) < 2: imgs.append(imgs[-1]) return imgs # ============================================================================ # Server config helpers (used at app launch) # ============================================================================ DEFAULT_SERVER_CONFIG = _from_graph("DEFAULT_SERVER_CONFIG", { "server_name": "0.0.0.0", "server_port": int(os.environ.get("PORT", os.environ.get("SERVER_PORT", 7860))), "share": False, # gradio share link "debug": False }) def get_server_config() -> Dict[str, Any]: """Return server config for demo.launch(**cfg).""" cfg = DEFAULT_SERVER_CONFIG.copy() # Allow environment overrides try: if os.environ.get("GRADIO_SHARE", "").lower() in ("1", "true", "yes"): cfg["share"] = True except Exception: pass return cfg def log_launch_banner(port: int): """Small friendly banner used at startup logs.""" try: log.info("=" * 60) log.info(f"Launching Gradio app on port {port} β€” {APP_TITLE} {APP_TITLE_EMOJI}") log.info("=" * 60) except Exception: pass # ============================================================================ # Small validation helper used by app_gradio feedback flow # ============================================================================ def validate_rating(rating: int): if not isinstance(rating, int): raise ValueError("Rating must be integer") if rating < RATING_MIN or rating > RATING_MAX: raise ValueError(f"Rating must be between {RATING_MIN} and {RATING_MAX}") return True # ---------------------------------------------------------------------------- # INITIAL STATUS MESSAGE (used by app_gradio) # ---------------------------------------------------------------------------- INITIAL_STATUS = "πŸ’¬ Ready to help" # ---------------------------------------------------------------------------- # DEFAULT CHECKBOX STATES & GOVERNANCE FLAGS (used in app_gradio sidebar) # ---------------------------------------------------------------------------- # Liberal defaults (auto-approve & flexible budgets enabled by default) DEFAULT_FLEXIBLE_CHECKBOX = True DEFAULT_AUTO_ACCEPT_CHECKBOX = True # Escalation is optional, off by default DEFAULT_ALLOW_ESCALATION = False # ---------------------------------------------------------------------------- # ADD MISSING UI LABELS (small, safe defaults) # ---------------------------------------------------------------------------- # Label for the "auto accept" checkbox in the UI sidebar LABEL_AUTO_ACCEPT = "Auto-accept 'approve with warning' decisions" # (Ensure there's also a corresponding checkbox default; safe default = True) DEFAULT_AUTO_ACCEPT_CHECKBOX = globals().get("DEFAULT_AUTO_ACCEPT_CHECKBOX", True) # ---------------------------------------------------------------------------- # FILES / ARTIFACTS UI LABELS # ---------------------------------------------------------------------------- # Label shown on the "download artifacts" Files component LABEL_DOWNLOAD_ARTIFACTS = "Download artifacts" # Helpful siblings used elsewhere in the UI (safe defaults) LABEL_UPLOAD_FILES = globals().get("LABEL_UPLOAD_FILES", "Upload files") LABEL_DOWNLOAD_ZIP = globals().get("LABEL_DOWNLOAD_ZIP", "Download all as .zip") PLACEHOLDER_NO_FILES = globals().get("PLACEHOLDER_NO_FILES", "No files available") # ---------------------------------------------------------------------------- # PLAN DISPLAY / ESTIMATION TEXT CONSTANTS (used by start_estimation) # ---------------------------------------------------------------------------- # Section headers PLAN_HEADER = "**πŸ“‹ Execution Plan:**\n" PLAN_ESTIMATE_HEADER = "\n\n**πŸ“Š Estimate:**\n" # Step prefix used in list output PLAN_STEP_PREFIX = "- " # Formatting patterns for estimation details PLAN_ATTEMPTS_FORMAT = "- Attempts: up to **{}**\n" PLAN_COST_FORMAT = "- Estimated cost: **${}**\n" PLAN_BUFFER_FORMAT = "- With 20% buffer: **${:.2f}**" # Default initial max loops used by estimation when no override provided DEFAULT_MAX_LOOPS_INITIAL = globals().get("DEFAULT_MAX_LOOPS_INITIAL", 0) # Budget multipliers (used when showing cost with buffer) BUDGET_BUFFER_MULTIPLIER = globals().get("BUDGET_BUFFER_MULTIPLIER", 1.20) # ---------------------------------------------------------------------------- # Additional safe defaults to prevent missing-attribute errors (add these) # ---------------------------------------------------------------------------- # Feedback / logging helpers LOG_FEEDBACK_SUBMISSION_FAILED = "Failed saving feedback" FEEDBACK_THANK_YOU_MESSAGES = globals().get("FEEDBACK_THANK_YOU_MESSAGES", [ "Thanks β€” your feedback helps us improve!", "Appreciate your feedback β€” thank you!", "Thanks! We logged your feedback." ]) # Feedback defaults / counts DEFAULT_COMMENT = "No comment provided" DEFAULT_RUN_COST = 0.0 DEFAULT_AVG_REWARD = 0.0 DEFAULT_FEEDBACK_COUNT = 0 # Optional feedback agent hooks (module.function style) - leave None if unused FEEDBACK_AGENT_MODULE = None FEEDBACK_AGENT_FUNCTION = None # Download / artifacts label (if not already present) LABEL_DOWNLOAD_ARTIFACTS = globals().get("LABEL_DOWNLOAD_ARTIFACTS", "Download artifacts") # Default budget value shown in the UI (USD) DEFAULT_BUDGET_DISPLAY = globals().get("DEFAULT_BUDGET_DISPLAY", 0.10) # ============================================================================ # Export list for other modules # ============================================================================ __all__ = [ # Paths "OUT_DIR", "OUTPUTS_DIR", "UPLOADS_DIR", "USER_ARTIFACTS_DIR", "EXPORTS_DIR", "ARTIFACT_REGISTRY_FILE", "FEEDBACK_STORAGE_DIR", "DIR_EXIST_OK", # Theme & UI "get_theme", "APP_TITLE", "APP_TITLE_EMOJI", "APP_SUBTITLE", "CUSTOM_CSS", "GRADIO_THEME", # Context "SHOW_CONTEXT_INDICATOR", "CONTEXT_INDICATOR_NEW", "CONTEXT_INDICATOR_FOLLOW_UP", "CONTEXT_INDICATOR_FORMAT", # Default config "DEFAULT_CONFIG", "get_default_config", # UI constants "CHAT_COLUMN_SCALE", "SIDEBAR_COLUMN_SCALE", "CHATBOT_HEIGHT", "CHATBOT_SHOW_LABEL", "PLACEHOLDER_MESSAGE_INPUT", "INPUT_TEXTBOX_SCALE", "INPUT_LINES", "INPUT_SHOW_LABEL", "BUTTON_SEND", "BUTTON_PROCEED", "BUTTON_CANCEL", "BUTTON_NEW_CHAT", "BUTTON_RESET", "BUTTON_REFRESH", "BUTTON_SUBMIT_FEEDBACK", "BUTTON_VARIANT_PRIMARY", "BUTTON_VARIANT_SECONDARY", "BUTTON_VARIANT_STOP", "BUTTON_SIZE_SMALL", "BUTTON_SIZE_LARGE", "PROCEED_BUTTON_SCALE", "CANCEL_BUTTON_SCALE", "SUBMIT_BUTTON_SCALE", "APPROVAL_BOX_DEFAULT_VISIBLE", # Budget & tiers "LABEL_MAX_BUDGET", "BUDGET_DEFAULT_VALUE", "BUDGET_MINIMUM", "BUDGET_STEP", "BUDGET_INPUT_SCALE", "LABEL_FLEXIBLE_BUDGET", "LABEL_PREFERRED_TIER", "TIER_CHOICES", "TIER_DEFAULT", # Feedback & files "SECTION_FEEDBACK", "FEEDBACK_PURPOSE_TEXT", "FEEDBACK_CATEGORIES", "LABEL_RATING", "RATING_MIN", "RATING_MAX", "RATING_DEFAULT_VALUE", "LABEL_FEEDBACK_COMMENTS", "FEEDBACK_PLACEHOLDER", "SECTION_FILES_ARTIFACTS", "LABEL_UPLOAD_FILES", "ALLOWED_FILE_TYPES", "UPLOAD_STATUS_SHOW_LABEL", "PLACEHOLDER_NO_FILES", "SECTION_DEBUG", "ACCORDION_DEBUG_OPEN", "LABEL_AGENT_STATE", "DEBUG_JSON_VISIBLE", "FEEDBACK_THANK_YOU_MESSAGES", # Messages & status "RESET_SUCCESS_MESSAGE", "RESET_LOG_MESSAGE", "RESET_ERROR_MESSAGE_PREFIX", "NO_FILE_UPLOADED_MESSAGE", "FILE_UPLOAD_SUCCESS_PREFIX", "FILE_UPLOAD_SUCCESS_SUFFIX", "NO_ARTIFACTS_MESSAGE", "NO_ARTIFACTS_GENERATED_MESSAGE", "CLEAR_CONVERSATION_MESSAGE", "ASSISTANT_THINKING_PLACEHOLDER", "STATUS_ANALYZING", "STATUS_READY", "STATUS_AWAITING_APPROVAL", "STATUS_TASK_APPROVED", "STATUS_TASK_COMPLETE", "STATUS_PARTIAL_COMPLETION", "STATUS_CANCELLED", "STATUS_ERROR_PREFIX", "ERROR_EXECUTION_PREFIX", # Helpers "get_avatar_images", "get_server_config", "log_launch_banner", "validate_rating", "INITIAL_STATUS", "DEFAULT_FLEXIBLE_CHECKBOX", "DEFAULT_AUTO_ACCEPT_CHECKBOX", "DEFAULT_ALLOW_ESCALATION", "LABEL_AUTO_ACCEPT", "DEFAULT_AUTO_ACCEPT_CHECKBOX", # UI / theme / metadata & helpers 'APP_TITLE', 'APP_TITLE_EMOJI', 'APP_SUBTITLE', 'CUSTOM_CSS', 'GRADIO_THEME', 'get_theme', # Context indicators & initial status 'SHOW_CONTEXT_INDICATOR', 'CONTEXT_INDICATOR_NEW', 'CONTEXT_INDICATOR_FOLLOW_UP', 'CONTEXT_INDICATOR_FORMAT', 'INITIAL_STATUS', # Paths & artifact flags 'USER_ARTIFACTS_DIR', 'DIR_EXIST_OK', # Avatar helpers 'get_avatar_images', 'AVATAR_USER', 'AVATAR_BOT', # Default config & helpers 'DEFAULT_CONFIG', 'get_default_config', # Checkbox defaults / governance & labels 'DEFAULT_FLEXIBLE_CHECKBOX', 'DEFAULT_AUTO_ACCEPT_CHECKBOX', 'DEFAULT_ALLOW_ESCALATION', 'LABEL_AUTO_ACCEPT', # Button & UI labels commonly used 'BUTTON_SEND', 'BUTTON_PROCEED', 'BUTTON_CANCEL', 'BUTTON_NEW_CHAT', 'BUTTON_RESET', 'BUTTON_REFRESH', 'BUTTON_SUBMIT_FEEDBACK', # Placeholders / small text 'ASSISTANT_THINKING_PLACEHOLDER', 'PLACEHOLDER_MESSAGE_INPUT', 'PLACEHOLDER_NO_FILES', # Server / logging helpers 'get_server_config', 'log_launch_banner', # Validation 'validate_rating', #artifacts 'LABEL_DOWNLOAD_ARTIFACTS', 'LABEL_UPLOAD_FILES', 'LABEL_DOWNLOAD_ZIP', 'PLACEHOLDER_NO_FILES', #plan 'PLAN_HEADER', 'PLAN_ESTIMATE_HEADER', 'PLAN_STEP_PREFIX', 'PLAN_ATTEMPTS_FORMAT', 'PLAN_COST_FORMAT', 'PLAN_BUFFER_FORMAT', 'DEFAULT_MAX_LOOPS_INITIAL', 'BUDGET_BUFFER_MULTIPLIER', 'LOG_FEEDBACK_SUBMISSION_FAILED', 'DEFAULT_COMMENT', 'DEFAULT_RUN_COST', 'DEFAULT_AVG_REWARD', 'DEFAULT_FEEDBACK_COUNT', 'FEEDBACK_AGENT_MODULE', 'FEEDBACK_AGENT_FUNCTION', 'LABEL_DOWNLOAD_ARTIFACTS', 'DEFAULT_BUDGET_DISPLAY' ]