Files
hack/tools/scripts/llm-key-hunter/results/_cache/content/3113y_isaac-ai-agent.json
T

1 line
40 KiB
JSON

{"repo": "3113y/isaac-ai-agent", "files": {"src/isaac_agent/llm_factory.py": {"1fc3992b9b97157f0902bd10ce473a9fedada7e0": {"t": 1785745429.8076348, "n": 5633, "h": "46b65aeadbabd4fa", "c": "\"\"\"\r\nLLM Factory - Initialize language models from different providers\r\nSupports: OpenAI (GPT), GLM (Qwen/智谱), Deepseek\r\n\"\"\"\r\n\r\nfrom typing import Optional\r\nfrom loguru import logger\r\nfrom langchain_core.language_models import BaseLanguageModel\r\n\r\nfrom isaac_agent.config import settings\r\n\r\n\r\ndef _init_openai_llm(\r\n api_key: Optional[str] = None,\r\n model: Optional[str] = None,\r\n temperature: Optional[float] = None,\r\n max_tokens: Optional[int] = None,\r\n) -> BaseLanguageModel:\r\n \"\"\"Initialize OpenAI ChatGPT model\"\"\"\r\n try:\r\n from langchain_openai import ChatOpenAI\r\n except ImportError:\r\n raise ImportError(\"Install: pip install langchain-openai\")\r\n \r\n api_key = api_key or settings.openai_api_key\r\n if not api_key:\r\n raise ValueError(\"OpenAI API key not provided. Set OPENAI_API_KEY env var\")\r\n \r\n model = model or settings.openai_model\r\n temperature = temperature if temperature is not None else settings.temperature\r\n max_tokens = max_tokens or settings.max_tokens\r\n \r\n logger.info(f\"🤖 Initializing OpenAI ChatGPT: {model}\")\r\n return ChatOpenAI(\r\n model=model,\r\n api_key=api_key,\r\n temperature=temperature,\r\n max_tokens=max_tokens,\r\n )\r\n\r\n\r\ndef _init_glm_llm(\r\n api_key: Optional[str] = None,\r\n model: Optional[str] = None,\r\n temperature: Optional[float] = None,\r\n max_tokens: Optional[int] = None,\r\n) -> BaseLanguageModel:\r\n \"\"\"Initialize GLM model (智谱/Qwen/通义千问)\"\"\"\r\n try:\r\n from langchain_community.chat_models.zhipuai import ChatZhipuAI\r\n except ImportError:\r\n # Fallback to LangChain integration if available\r\n try:\r\n from langchain_openai import ChatOpenAI\r\n logger.warning(\"⚠️ langchain-community not installed, using OpenAI mock\")\r\n return _init_openai_llm(api_key, model, temperature, max_tokens)\r\n except ImportError:\r\n raise ImportError(\"Install: pip install langchain-community langchain-openai\")\r\n \r\n api_key = api_key or settings.glm_api_key\r\n if not api_key:\r\n raise ValueError(\"GLM API key not provided. Set GLM_API_KEY env var\")\r\n \r\n model = model or settings.glm_model\r\n temperature = temperature if temperature is not None else settings.temperature\r\n max_tokens = max_tokens or settings.max_tokens\r\n \r\n logger.info(f\"🤖 Initializing GLM/Qwen: {model}\")\r\n return ChatZhipuAI(\r\n api_key=api_key,\r\n model=model,\r\n temperature=temperature,\r\n max_tokens=max_tokens,\r\n )\r\n\r\n\r\ndef _init_deepseek_llm(\r\n api_key: Optional[str] = None,\r\n model: Optional[str] = None,\r\n temperature: Optional[float] = None,\r\n max_tokens: Optional[int] = None,\r\n) -> BaseLanguageModel:\r\n \"\"\"Initialize Deepseek model\"\"\"\r\n try:\r\n from langchain_openai import ChatOpenAI\r\n except ImportError:\r\n raise ImportError(\"Install: pip install langchain-openai\")\r\n \r\n api_key = api_key or settings.deepseek_api_key\r\n if not api_key:\r\n raise ValueError(\"Deepseek API key not provided. Set DEEPSEEK_API_KEY env var\")\r\n \r\n model = model or settings.deepseek_model\r\n temperature = temperature if temperature is not None else settings.temperature\r\n max_tokens = max_tokens or settings.max_tokens\r\n \r\n logger.info(f\"🤖 Initializing Deepseek: {model}\")\r\n # Deepseek compatible with OpenAI API\r\n return ChatOpenAI(\r\n model=model,\r\n api_key=api_key,\r\n base_url=\"https://api.deepseek.com/v1\",\r\n temperature=temperature,\r\n max_tokens=max_tokens,\r\n )\r\n\r\n\r\n# Default models for each provider when user doesn't specify\r\n_DEFAULT_MODELS = {\r\n \"openai\": \"gpt-4-turbo\",\r\n \"glm\": \"glm-4\",\r\n \"deepseek\": \"deepseek-chat\",\r\n}\r\n\r\n\r\ndef init_llm(\r\n provider: Optional[str] = None,\r\n model: Optional[str] = None,\r\n api_key: Optional[str] = None,\r\n temperature: Optional[float] = None,\r\n max_tokens: Optional[int] = None,\r\n) -> Optional[BaseLanguageModel]:\r\n \"\"\"\r\n Initialize LLM from provider.\r\n\r\n The api_key parameter takes priority over env vars / .env config.\r\n This allows each user to supply their own key in the UI.\r\n\r\n Args:\r\n provider: LLM provider (\"openai\", \"glm\", \"deepseek\")\r\n model: Model name to use (auto-filled from defaults if omitted)\r\n api_key: API key for the provider — user-provided, takes priority\r\n temperature: Temperature for sampling\r\n max_tokens: Max tokens to generate\r\n\r\n Returns:\r\n BaseLanguageModel instance or None if provider not configured\r\n \"\"\"\r\n provider = provider or settings.llm_provider\r\n\r\n if not provider:\r\n logger.warning(\"No LLM provider configured\")\r\n return None\r\n\r\n provider = provider.lower().strip()\r\n\r\n # Auto-fill model name from defaults if not specified\r\n if not model:\r\n model = _DEFAULT_MODELS.get(provider, settings.openai_model)\r\n\r\n try:\r\n if provider == \"openai\" or provider == \"gpt\":\r\n return _init_openai_llm(api_key, model, temperature, max_tokens)\r\n elif provider == \"glm\" or provider == \"qwen\":\r\n return _init_glm_llm(api_key, model, temperature, max_tokens)\r\n elif provider == \"deepseek\":\r\n return _init_deepseek_llm(api_key, model, temperature, max_tokens)\r\n else:\r\n logger.error(f\"Unknown LLM provider: {provider}\")\r\n logger.info(\"Supported providers: openai, glm, deepseek\")\r\n return None\r\n except Exception as e:\r\n logger.error(f\"Failed to initialize {provider} LLM: {e}\")\r\n return None\r\n"}, "4568c8300d4f2037c941d719b79df088f0b3cc57": {"t": 1785753117.603297, "n": 5633, "h": "46b65aeadbabd4fa", "c": "\"\"\"\r\nLLM Factory - Initialize language models from different providers\r\nSupports: OpenAI (GPT), GLM (Qwen/智谱), Deepseek\r\n\"\"\"\r\n\r\nfrom typing import Optional\r\nfrom loguru import logger\r\nfrom langchain_core.language_models import BaseLanguageModel\r\n\r\nfrom isaac_agent.config import settings\r\n\r\n\r\ndef _init_openai_llm(\r\n api_key: Optional[str] = None,\r\n model: Optional[str] = None,\r\n temperature: Optional[float] = None,\r\n max_tokens: Optional[int] = None,\r\n) -> BaseLanguageModel:\r\n \"\"\"Initialize OpenAI ChatGPT model\"\"\"\r\n try:\r\n from langchain_openai import ChatOpenAI\r\n except ImportError:\r\n raise ImportError(\"Install: pip install langchain-openai\")\r\n \r\n api_key = api_key or settings.openai_api_key\r\n if not api_key:\r\n raise ValueError(\"OpenAI API key not provided. Set OPENAI_API_KEY env var\")\r\n \r\n model = model or settings.openai_model\r\n temperature = temperature if temperature is not None else settings.temperature\r\n max_tokens = max_tokens or settings.max_tokens\r\n \r\n logger.info(f\"🤖 Initializing OpenAI ChatGPT: {model}\")\r\n return ChatOpenAI(\r\n model=model,\r\n api_key=api_key,\r\n temperature=temperature,\r\n max_tokens=max_tokens,\r\n )\r\n\r\n\r\ndef _init_glm_llm(\r\n api_key: Optional[str] = None,\r\n model: Optional[str] = None,\r\n temperature: Optional[float] = None,\r\n max_tokens: Optional[int] = None,\r\n) -> BaseLanguageModel:\r\n \"\"\"Initialize GLM model (智谱/Qwen/通义千问)\"\"\"\r\n try:\r\n from langchain_community.chat_models.zhipuai import ChatZhipuAI\r\n except ImportError:\r\n # Fallback to LangChain integration if available\r\n try:\r\n from langchain_openai import ChatOpenAI\r\n logger.warning(\"⚠️ langchain-community not installed, using OpenAI mock\")\r\n return _init_openai_llm(api_key, model, temperature, max_tokens)\r\n except ImportError:\r\n raise ImportError(\"Install: pip install langchain-community langchain-openai\")\r\n \r\n api_key = api_key or settings.glm_api_key\r\n if not api_key:\r\n raise ValueError(\"GLM API key not provided. Set GLM_API_KEY env var\")\r\n \r\n model = model or settings.glm_model\r\n temperature = temperature if temperature is not None else settings.temperature\r\n max_tokens = max_tokens or settings.max_tokens\r\n \r\n logger.info(f\"🤖 Initializing GLM/Qwen: {model}\")\r\n return ChatZhipuAI(\r\n api_key=api_key,\r\n model=model,\r\n temperature=temperature,\r\n max_tokens=max_tokens,\r\n )\r\n\r\n\r\ndef _init_deepseek_llm(\r\n api_key: Optional[str] = None,\r\n model: Optional[str] = None,\r\n temperature: Optional[float] = None,\r\n max_tokens: Optional[int] = None,\r\n) -> BaseLanguageModel:\r\n \"\"\"Initialize Deepseek model\"\"\"\r\n try:\r\n from langchain_openai import ChatOpenAI\r\n except ImportError:\r\n raise ImportError(\"Install: pip install langchain-openai\")\r\n \r\n api_key = api_key or settings.deepseek_api_key\r\n if not api_key:\r\n raise ValueError(\"Deepseek API key not provided. Set DEEPSEEK_API_KEY env var\")\r\n \r\n model = model or settings.deepseek_model\r\n temperature = temperature if temperature is not None else settings.temperature\r\n max_tokens = max_tokens or settings.max_tokens\r\n \r\n logger.info(f\"🤖 Initializing Deepseek: {model}\")\r\n # Deepseek compatible with OpenAI API\r\n return ChatOpenAI(\r\n model=model,\r\n api_key=api_key,\r\n base_url=\"https://api.deepseek.com/v1\",\r\n temperature=temperature,\r\n max_tokens=max_tokens,\r\n )\r\n\r\n\r\n# Default models for each provider when user doesn't specify\r\n_DEFAULT_MODELS = {\r\n \"openai\": \"gpt-4-turbo\",\r\n \"glm\": \"glm-4\",\r\n \"deepseek\": \"deepseek-chat\",\r\n}\r\n\r\n\r\ndef init_llm(\r\n provider: Optional[str] = None,\r\n model: Optional[str] = None,\r\n api_key: Optional[str] = None,\r\n temperature: Optional[float] = None,\r\n max_tokens: Optional[int] = None,\r\n) -> Optional[BaseLanguageModel]:\r\n \"\"\"\r\n Initialize LLM from provider.\r\n\r\n The api_key parameter takes priority over env vars / .env config.\r\n This allows each user to supply their own key in the UI.\r\n\r\n Args:\r\n provider: LLM provider (\"openai\", \"glm\", \"deepseek\")\r\n model: Model name to use (auto-filled from defaults if omitted)\r\n api_key: API key for the provider — user-provided, takes priority\r\n temperature: Temperature for sampling\r\n max_tokens: Max tokens to generate\r\n\r\n Returns:\r\n BaseLanguageModel instance or None if provider not configured\r\n \"\"\"\r\n provider = provider or settings.llm_provider\r\n\r\n if not provider:\r\n logger.warning(\"No LLM provider configured\")\r\n return None\r\n\r\n provider = provider.lower().strip()\r\n\r\n # Auto-fill model name from defaults if not specified\r\n if not model:\r\n model = _DEFAULT_MODELS.get(provider, settings.openai_model)\r\n\r\n try:\r\n if provider == \"openai\" or provider == \"gpt\":\r\n return _init_openai_llm(api_key, model, temperature, max_tokens)\r\n elif provider == \"glm\" or provider == \"qwen\":\r\n return _init_glm_llm(api_key, model, temperature, max_tokens)\r\n elif provider == \"deepseek\":\r\n return _init_deepseek_llm(api_key, model, temperature, max_tokens)\r\n else:\r\n logger.error(f\"Unknown LLM provider: {provider}\")\r\n logger.info(\"Supported providers: openai, glm, deepseek\")\r\n return None\r\n except Exception as e:\r\n logger.error(f\"Failed to initialize {provider} LLM: {e}\")\r\n return None\r\n"}, "30080573120fda3e46a2f01c09e35e43f389ff6d": {"t": 1785753119.6696725, "n": 5135, "h": "45c2e488047ad031", "c": "\"\"\"\r\nLLM Factory - Initialize language models from different providers\r\nSupports: OpenAI (GPT), GLM (Qwen/智谱), Deepseek\r\n\"\"\"\r\n\r\nfrom typing import Optional\r\nfrom loguru import logger\r\nfrom langchain_core.language_model.base import BaseLanguageModel\r\n\r\nfrom isaac_agent.config import settings\r\n\r\n\r\ndef _init_openai_llm(\r\n api_key: Optional[str] = None,\r\n model: Optional[str] = None,\r\n temperature: Optional[float] = None,\r\n max_tokens: Optional[int] = None,\r\n) -> BaseLanguageModel:\r\n \"\"\"Initialize OpenAI ChatGPT model\"\"\"\r\n try:\r\n from langchain_openai import ChatOpenAI\r\n except ImportError:\r\n raise ImportError(\"Install: pip install langchain-openai\")\r\n \r\n api_key = api_key or settings.openai_api_key\r\n if not api_key:\r\n raise ValueError(\"OpenAI API key not provided. Set OPENAI_API_KEY env var\")\r\n \r\n model = model or settings.openai_model\r\n temperature = temperature if temperature is not None else settings.temperature\r\n max_tokens = max_tokens or settings.max_tokens\r\n \r\n logger.info(f\"🤖 Initializing OpenAI ChatGPT: {model}\")\r\n return ChatOpenAI(\r\n model=model,\r\n api_key=api_key,\r\n temperature=temperature,\r\n max_tokens=max_tokens,\r\n )\r\n\r\n\r\ndef _init_glm_llm(\r\n api_key: Optional[str] = None,\r\n model: Optional[str] = None,\r\n temperature: Optional[float] = None,\r\n max_tokens: Optional[int] = None,\r\n) -> BaseLanguageModel:\r\n \"\"\"Initialize GLM model (智谱/Qwen/通义千问)\"\"\"\r\n try:\r\n from langchain_community.chat_models.zhipuai import ChatZhipuAI\r\n except ImportError:\r\n # Fallback to LangChain integration if available\r\n try:\r\n from langchain_openai import ChatOpenAI\r\n logger.warning(\"⚠️ langchain-community not installed, using OpenAI mock\")\r\n return _init_openai_llm(api_key, model, temperature, max_tokens)\r\n except ImportError:\r\n raise ImportError(\"Install: pip install langchain-community langchain-openai\")\r\n \r\n api_key = api_key or settings.glm_api_key\r\n if not api_key:\r\n raise ValueError(\"GLM API key not provided. Set GLM_API_KEY env var\")\r\n \r\n model = model or settings.glm_model\r\n temperature = temperature if temperature is not None else settings.temperature\r\n max_tokens = max_tokens or settings.max_tokens\r\n \r\n logger.info(f\"🤖 Initializing GLM/Qwen: {model}\")\r\n return ChatZhipuAI(\r\n api_key=api_key,\r\n model=model,\r\n temperature=temperature,\r\n max_tokens=max_tokens,\r\n )\r\n\r\n\r\ndef _init_deepseek_llm(\r\n api_key: Optional[str] = None,\r\n model: Optional[str] = None,\r\n temperature: Optional[float] = None,\r\n max_tokens: Optional[int] = None,\r\n) -> BaseLanguageModel:\r\n \"\"\"Initialize Deepseek model\"\"\"\r\n try:\r\n from langchain_openai import ChatOpenAI\r\n except ImportError:\r\n raise ImportError(\"Install: pip install langchain-openai\")\r\n \r\n api_key = api_key or settings.deepseek_api_key\r\n if not api_key:\r\n raise ValueError(\"Deepseek API key not provided. Set DEEPSEEK_API_KEY env var\")\r\n \r\n model = model or settings.deepseek_model\r\n temperature = temperature if temperature is not None else settings.temperature\r\n max_tokens = max_tokens or settings.max_tokens\r\n \r\n logger.info(f\"🤖 Initializing Deepseek: {model}\")\r\n # Deepseek compatible with OpenAI API\r\n return ChatOpenAI(\r\n model=model,\r\n api_key=api_key,\r\n base_url=\"https://api.deepseek.com/v1\",\r\n temperature=temperature,\r\n max_tokens=max_tokens,\r\n )\r\n\r\n\r\ndef init_llm(\r\n provider: Optional[str] = None,\r\n model: Optional[str] = None,\r\n api_key: Optional[str] = None,\r\n temperature: Optional[float] = None,\r\n max_tokens: Optional[int] = None,\r\n) -> Optional[BaseLanguageModel]:\r\n \"\"\"\r\n Initialize LLM from provider\r\n \r\n Args:\r\n provider: LLM provider (\"openai\", \"glm\", \"deepseek\")\r\n model: Model name to use\r\n api_key: API key for the provider\r\n temperature: Temperature for sampling\r\n max_tokens: Max tokens to generate\r\n \r\n Returns:\r\n BaseLanguageModel instance or None if provider not configured\r\n \"\"\"\r\n provider = provider or settings.llm_provider\r\n \r\n if not provider:\r\n logger.warning(\"⚠️ No LLM provider configured\")\r\n return None\r\n \r\n provider = provider.lower().strip()\r\n \r\n try:\r\n if provider == \"openai\" or provider == \"gpt\":\r\n return _init_openai_llm(api_key, model, temperature, max_tokens)\r\n elif provider == \"glm\" or provider == \"qwen\":\r\n return _init_glm_llm(api_key, model, temperature, max_tokens)\r\n elif provider == \"deepseek\":\r\n return _init_deepseek_llm(api_key, model, temperature, max_tokens)\r\n else:\r\n logger.error(f\"❌ Unknown LLM provider: {provider}\")\r\n logger.info(\"✅ Supported providers: openai, glm, deepseek\")\r\n return None\r\n except Exception as e:\r\n logger.error(f\"❌ Failed to initialize {provider} LLM: {e}\")\r\n return None\r\n"}}, "src/isaac_agent/desktop/settings_dialog.py": {"1fc3992b9b97157f0902bd10ce473a9fedada7e0": {"t": 1785746440.4739738, "n": 10369, "h": "7946006c569884e3", "c": "\"\"\"\nSettings dialog — configure LLM provider, API keys, model, and Isaac paths.\n\nReplaces the old .env editing workflow with a proper GUI.\n\"\"\"\n\nimport os\nfrom pathlib import Path\nfrom typing import Optional\n\nfrom PyQt6.QtWidgets import (\n QDialog, QVBoxLayout, QHBoxLayout, QFormLayout, QLineEdit,\n QComboBox, QPushButton, QTabWidget, QWidget, QFileDialog,\n QSpinBox, QDoubleSpinBox, QGroupBox, QDialogButtonBox,\n QLabel, QMessageBox,\n)\nfrom PyQt6.QtCore import Qt\n\nfrom isaac_agent.config import settings, Settings\nfrom isaac_agent.tools.isaac_path_resolver import resolve_all_paths\n\n\nclass SettingsDialog(QDialog):\n \"\"\"Application settings dialog.\"\"\"\n\n def __init__(self, parent=None):\n super().__init__(parent)\n self.setWindowTitle(\"Settings — Isaac AI Agent\")\n self.setMinimumSize(550, 500)\n self.setModal(True)\n self._setup_ui()\n self._load_settings()\n\n def _setup_ui(self):\n layout = QVBoxLayout(self)\n\n tabs = QTabWidget()\n\n # ── LLM Tab ─────────────────────────────────────────────────────\n llm_tab = QWidget()\n llm_layout = QVBoxLayout(llm_tab)\n\n # Provider group\n prov_group = QGroupBox(\"LLM Provider\")\n prov_form = QFormLayout()\n self._provider_combo = QComboBox()\n self._provider_combo.addItems([\"openai\", \"deepseek\", \"glm\"])\n self._provider_combo.currentTextChanged.connect(self._on_provider_changed)\n prov_form.addRow(\"Provider:\", self._provider_combo)\n prov_group.setLayout(prov_form)\n llm_layout.addWidget(prov_group)\n\n # OpenAI settings\n self._openai_group = QGroupBox(\"OpenAI / DeepSeek\")\n openai_form = QFormLayout()\n self._openai_key = QLineEdit()\n self._openai_key.setEchoMode(QLineEdit.EchoMode.Password)\n self._openai_key.setPlaceholderText(\"sk-...\")\n openai_form.addRow(\"API Key:\", self._openai_key)\n self._openai_model = QComboBox()\n self._openai_model.setEditable(True)\n self._openai_model.addItems([\n \"gpt-4-turbo\", \"gpt-4o\", \"gpt-3.5-turbo\",\n \"deepseek-chat\", \"deepseek-coder\",\n ])\n openai_form.addRow(\"Model:\", self._openai_model)\n self._openai_group.setLayout(openai_form)\n llm_layout.addWidget(self._openai_group)\n\n # GLM settings\n self._glm_group = QGroupBox(\"GLM / ZhipuAI\")\n glm_form = QFormLayout()\n self._glm_key = QLineEdit()\n self._glm_key.setEchoMode(QLineEdit.EchoMode.Password)\n glm_form.addRow(\"API Key:\", self._glm_key)\n self._glm_model = QComboBox()\n self._glm_model.setEditable(True)\n self._glm_model.addItems([\"glm-4\", \"glm-4-flash\"])\n glm_form.addRow(\"Model:\", self._glm_model)\n self._glm_group.setLayout(glm_form)\n llm_layout.addWidget(self._glm_group)\n\n # Common settings\n common_group = QGroupBox(\"Generation Settings\")\n common_form = QFormLayout()\n self._temperature = QDoubleSpinBox()\n self._temperature.setRange(0.0, 2.0)\n self._temperature.setSingleStep(0.1)\n self._temperature.setValue(0.7)\n common_form.addRow(\"Temperature:\", self._temperature)\n self._max_tokens = QSpinBox()\n self._max_tokens.setRange(256, 32768)\n self._max_tokens.setSingleStep(256)\n self._max_tokens.setValue(4096)\n common_form.addRow(\"Max Tokens:\", self._max_tokens)\n common_group.setLayout(common_form)\n llm_layout.addWidget(common_group)\n\n llm_layout.addStretch()\n tabs.addTab(llm_tab, \"🤖 LLM\")\n\n # ── Paths Tab ───────────────────────────────────────────────────\n paths_tab = QWidget()\n paths_layout = QVBoxLayout(paths_tab)\n\n paths_group = QGroupBox(\"Isaac Paths\")\n paths_form = QFormLayout()\n\n self._mods_dir = QLineEdit()\n self._mods_dir.setPlaceholderText(\"Auto-detected or select manually...\")\n mods_browse = QPushButton(\"Browse...\")\n mods_browse.clicked.connect(lambda: self._browse_dir(self._mods_dir, \"Select Mods Directory\"))\n mods_row = QHBoxLayout()\n mods_row.addWidget(self._mods_dir, stretch=1)\n mods_row.addWidget(mods_browse)\n paths_form.addRow(\"Mods Dir:\", mods_row)\n\n self._log_file = QLineEdit()\n self._log_file.setPlaceholderText(\"Auto-detected or select manually...\")\n log_browse = QPushButton(\"Browse...\")\n log_browse.clicked.connect(lambda: self._browse_file(self._log_file, \"Select log.txt\", \"Text Files (*.txt)\"))\n log_row = QHBoxLayout()\n log_row.addWidget(self._log_file, stretch=1)\n log_row.addWidget(log_browse)\n paths_form.addRow(\"Log File:\", log_row)\n\n paths_group.setLayout(paths_form)\n paths_layout.addWidget(paths_group)\n\n detect_btn = QPushButton(\"🔍 Auto-Detect Paths\")\n detect_btn.clicked.connect(self._auto_detect)\n paths_layout.addWidget(detect_btn)\n\n paths_layout.addStretch()\n tabs.addTab(paths_tab, \"📁 Paths\")\n\n # ── Data Tab ────────────────────────────────────────────────────\n data_tab = QWidget()\n data_layout = QVBoxLayout(data_tab)\n\n data_group = QGroupBox(\"RAG & Data\")\n data_form = QFormLayout()\n self._rag_path = QLineEdit()\n self._rag_path.setPlaceholderText(\"./processed_docs/rag_knowledge_base.json\")\n data_form.addRow(\"RAG KB:\", self._rag_path)\n self._faiss_path = QLineEdit()\n self._faiss_path.setPlaceholderText(\"./data/isaac_api.faiss\")\n data_form.addRow(\"FAISS Index:\", self._faiss_path)\n self._xml_cache = QLineEdit()\n self._xml_cache.setPlaceholderText(\"./data/xml_schemas_cache.json\")\n data_form.addRow(\"XML Cache:\", self._xml_cache)\n data_group.setLayout(data_form)\n data_layout.addWidget(data_group)\n\n data_layout.addStretch()\n tabs.addTab(data_tab, \"💾 Data\")\n\n layout.addWidget(tabs)\n\n # ── Dialog Buttons ──────────────────────────────────────────────\n buttons = QDialogButtonBox(\n QDialogButtonBox.StandardButton.Ok |\n QDialogButtonBox.StandardButton.Cancel |\n QDialogButtonBox.StandardButton.Apply\n )\n buttons.accepted.connect(self._save_and_accept)\n buttons.rejected.connect(self.reject)\n buttons.button(QDialogButtonBox.StandardButton.Apply).clicked.connect(self._save_settings)\n layout.addWidget(buttons)\n\n def _load_settings(self):\n \"\"\"Populate fields from current settings.\"\"\"\n self._provider_combo.setCurrentText(settings.llm_provider)\n self._openai_key.setText(settings.openai_api_key or \"\")\n self._openai_model.setCurrentText(settings.openai_model)\n self._glm_key.setText(settings.glm_api_key or \"\")\n self._glm_model.setCurrentText(settings.glm_model)\n self._temperature.setValue(settings.temperature)\n self._max_tokens.setValue(settings.max_tokens)\n self._mods_dir.setText(settings.isaac_mod_dir or \"\")\n self._log_file.setText(settings.detected_log_file or \"\")\n self._rag_path.setText(settings.rag_kb_path)\n self._faiss_path.setText(settings.faiss_index_path)\n self._xml_cache.setText(settings.xml_schema_cache_path)\n self._on_provider_changed(self._provider_combo.currentText())\n\n def _on_provider_changed(self, provider: str):\n \"\"\"Show/hide groups based on selected provider.\"\"\"\n is_openai = provider in (\"openai\", \"deepseek\")\n self._openai_group.setVisible(is_openai)\n self._glm_group.setVisible(provider == \"glm\")\n\n def _auto_detect(self):\n \"\"\"Auto-detect Isaac paths and update fields.\"\"\"\n try:\n paths = resolve_all_paths()\n if paths.get(\"mods_dir\"):\n self._mods_dir.setText(str(paths[\"mods_dir\"]))\n if paths.get(\"log_file\"):\n self._log_file.setText(str(paths[\"log_file\"]))\n QMessageBox.information(self, \"Detection Complete\", f\"Found:\\nMods: {paths.get('mods_dir')}\\nLog: {paths.get('log_file')}\")\n except Exception as exc:\n QMessageBox.warning(self, \"Detection Failed\", str(exc))\n\n def _browse_dir(self, target: QLineEdit, title: str):\n path = QFileDialog.getExistingDirectory(self, title, target.text() or os.path.expanduser(\"~\"))\n if path:\n target.setText(path)\n\n def _browse_file(self, target: QLineEdit, title: str, filter_str: str):\n path, _ = QFileDialog.getOpenFileName(self, title, target.text() or os.path.expanduser(\"~\"), filter_str)\n if path:\n target.setText(path)\n\n def _save_settings(self):\n \"\"\"Write settings to .env file.\"\"\"\n env_path = Path(\".env\")\n env_lines = {}\n\n # Read existing .env\n if env_path.exists():\n for line in env_path.read_text().splitlines():\n line = line.strip()\n if \"=\" in line and not line.startswith(\"#\"):\n key, _, val = line.partition(\"=\")\n env_lines[key.strip()] = val.strip().strip('\"')\n\n # Update with current values\n updates = {\n \"LLM_PROVIDER\": self._provider_combo.currentText(),\n \"OPENAI_API_KEY\": self._openai_key.text() or \"\",\n \"OPENAI_MODEL\": self._openai_model.currentText(),\n \"GLM_API_KEY\": self._glm_key.text() or \"\",\n \"GLM_MODEL\": self._glm_model.currentText(),\n \"LLM_TEMPERATURE\": str(self._temperature.value()),\n \"LLM_MAX_TOKENS\": str(self._max_tokens.value()),\n \"ISAAC_MOD_DIR\": self._mods_dir.text() or \"./mods\",\n \"RAG_KB_PATH\": self._rag_path.text() or \"\",\n \"FAISS_INDEX_PATH\": self._faiss_path.text() or \"\",\n \"XML_SCHEMA_CACHE_PATH\": self._xml_cache.text() or \"\",\n }\n env_lines.update(updates)\n\n # Write .env\n content = \"\\n\".join(f'{k}=\"{v}\"' for k, v in env_lines.items() if v)\n env_path.write_text(content + \"\\n\")\n\n # Reload settings (in-process)\n for key, value in updates.items():\n field_name = key.lower()\n if hasattr(settings, field_name):\n setattr(settings, field_name, value)\n\n def _save_and_accept(self):\n self._save_settings()\n self.accept()\n"}, "658fa099c706ec3f95488b3e011f22b633785a5e": {"t": 1785753117.6136382, "n": 10369, "h": "7946006c569884e3", "c": "\"\"\"\nSettings dialog — configure LLM provider, API keys, model, and Isaac paths.\n\nReplaces the old .env editing workflow with a proper GUI.\n\"\"\"\n\nimport os\nfrom pathlib import Path\nfrom typing import Optional\n\nfrom PyQt6.QtWidgets import (\n QDialog, QVBoxLayout, QHBoxLayout, QFormLayout, QLineEdit,\n QComboBox, QPushButton, QTabWidget, QWidget, QFileDialog,\n QSpinBox, QDoubleSpinBox, QGroupBox, QDialogButtonBox,\n QLabel, QMessageBox,\n)\nfrom PyQt6.QtCore import Qt\n\nfrom isaac_agent.config import settings, Settings\nfrom isaac_agent.tools.isaac_path_resolver import resolve_all_paths\n\n\nclass SettingsDialog(QDialog):\n \"\"\"Application settings dialog.\"\"\"\n\n def __init__(self, parent=None):\n super().__init__(parent)\n self.setWindowTitle(\"Settings — Isaac AI Agent\")\n self.setMinimumSize(550, 500)\n self.setModal(True)\n self._setup_ui()\n self._load_settings()\n\n def _setup_ui(self):\n layout = QVBoxLayout(self)\n\n tabs = QTabWidget()\n\n # ── LLM Tab ─────────────────────────────────────────────────────\n llm_tab = QWidget()\n llm_layout = QVBoxLayout(llm_tab)\n\n # Provider group\n prov_group = QGroupBox(\"LLM Provider\")\n prov_form = QFormLayout()\n self._provider_combo = QComboBox()\n self._provider_combo.addItems([\"openai\", \"deepseek\", \"glm\"])\n self._provider_combo.currentTextChanged.connect(self._on_provider_changed)\n prov_form.addRow(\"Provider:\", self._provider_combo)\n prov_group.setLayout(prov_form)\n llm_layout.addWidget(prov_group)\n\n # OpenAI settings\n self._openai_group = QGroupBox(\"OpenAI / DeepSeek\")\n openai_form = QFormLayout()\n self._openai_key = QLineEdit()\n self._openai_key.setEchoMode(QLineEdit.EchoMode.Password)\n self._openai_key.setPlaceholderText(\"sk-...\")\n openai_form.addRow(\"API Key:\", self._openai_key)\n self._openai_model = QComboBox()\n self._openai_model.setEditable(True)\n self._openai_model.addItems([\n \"gpt-4-turbo\", \"gpt-4o\", \"gpt-3.5-turbo\",\n \"deepseek-chat\", \"deepseek-coder\",\n ])\n openai_form.addRow(\"Model:\", self._openai_model)\n self._openai_group.setLayout(openai_form)\n llm_layout.addWidget(self._openai_group)\n\n # GLM settings\n self._glm_group = QGroupBox(\"GLM / ZhipuAI\")\n glm_form = QFormLayout()\n self._glm_key = QLineEdit()\n self._glm_key.setEchoMode(QLineEdit.EchoMode.Password)\n glm_form.addRow(\"API Key:\", self._glm_key)\n self._glm_model = QComboBox()\n self._glm_model.setEditable(True)\n self._glm_model.addItems([\"glm-4\", \"glm-4-flash\"])\n glm_form.addRow(\"Model:\", self._glm_model)\n self._glm_group.setLayout(glm_form)\n llm_layout.addWidget(self._glm_group)\n\n # Common settings\n common_group = QGroupBox(\"Generation Settings\")\n common_form = QFormLayout()\n self._temperature = QDoubleSpinBox()\n self._temperature.setRange(0.0, 2.0)\n self._temperature.setSingleStep(0.1)\n self._temperature.setValue(0.7)\n common_form.addRow(\"Temperature:\", self._temperature)\n self._max_tokens = QSpinBox()\n self._max_tokens.setRange(256, 32768)\n self._max_tokens.setSingleStep(256)\n self._max_tokens.setValue(4096)\n common_form.addRow(\"Max Tokens:\", self._max_tokens)\n common_group.setLayout(common_form)\n llm_layout.addWidget(common_group)\n\n llm_layout.addStretch()\n tabs.addTab(llm_tab, \"🤖 LLM\")\n\n # ── Paths Tab ───────────────────────────────────────────────────\n paths_tab = QWidget()\n paths_layout = QVBoxLayout(paths_tab)\n\n paths_group = QGroupBox(\"Isaac Paths\")\n paths_form = QFormLayout()\n\n self._mods_dir = QLineEdit()\n self._mods_dir.setPlaceholderText(\"Auto-detected or select manually...\")\n mods_browse = QPushButton(\"Browse...\")\n mods_browse.clicked.connect(lambda: self._browse_dir(self._mods_dir, \"Select Mods Directory\"))\n mods_row = QHBoxLayout()\n mods_row.addWidget(self._mods_dir, stretch=1)\n mods_row.addWidget(mods_browse)\n paths_form.addRow(\"Mods Dir:\", mods_row)\n\n self._log_file = QLineEdit()\n self._log_file.setPlaceholderText(\"Auto-detected or select manually...\")\n log_browse = QPushButton(\"Browse...\")\n log_browse.clicked.connect(lambda: self._browse_file(self._log_file, \"Select log.txt\", \"Text Files (*.txt)\"))\n log_row = QHBoxLayout()\n log_row.addWidget(self._log_file, stretch=1)\n log_row.addWidget(log_browse)\n paths_form.addRow(\"Log File:\", log_row)\n\n paths_group.setLayout(paths_form)\n paths_layout.addWidget(paths_group)\n\n detect_btn = QPushButton(\"🔍 Auto-Detect Paths\")\n detect_btn.clicked.connect(self._auto_detect)\n paths_layout.addWidget(detect_btn)\n\n paths_layout.addStretch()\n tabs.addTab(paths_tab, \"📁 Paths\")\n\n # ── Data Tab ────────────────────────────────────────────────────\n data_tab = QWidget()\n data_layout = QVBoxLayout(data_tab)\n\n data_group = QGroupBox(\"RAG & Data\")\n data_form = QFormLayout()\n self._rag_path = QLineEdit()\n self._rag_path.setPlaceholderText(\"./processed_docs/rag_knowledge_base.json\")\n data_form.addRow(\"RAG KB:\", self._rag_path)\n self._faiss_path = QLineEdit()\n self._faiss_path.setPlaceholderText(\"./data/isaac_api.faiss\")\n data_form.addRow(\"FAISS Index:\", self._faiss_path)\n self._xml_cache = QLineEdit()\n self._xml_cache.setPlaceholderText(\"./data/xml_schemas_cache.json\")\n data_form.addRow(\"XML Cache:\", self._xml_cache)\n data_group.setLayout(data_form)\n data_layout.addWidget(data_group)\n\n data_layout.addStretch()\n tabs.addTab(data_tab, \"💾 Data\")\n\n layout.addWidget(tabs)\n\n # ── Dialog Buttons ──────────────────────────────────────────────\n buttons = QDialogButtonBox(\n QDialogButtonBox.StandardButton.Ok |\n QDialogButtonBox.StandardButton.Cancel |\n QDialogButtonBox.StandardButton.Apply\n )\n buttons.accepted.connect(self._save_and_accept)\n buttons.rejected.connect(self.reject)\n buttons.button(QDialogButtonBox.StandardButton.Apply).clicked.connect(self._save_settings)\n layout.addWidget(buttons)\n\n def _load_settings(self):\n \"\"\"Populate fields from current settings.\"\"\"\n self._provider_combo.setCurrentText(settings.llm_provider)\n self._openai_key.setText(settings.openai_api_key or \"\")\n self._openai_model.setCurrentText(settings.openai_model)\n self._glm_key.setText(settings.glm_api_key or \"\")\n self._glm_model.setCurrentText(settings.glm_model)\n self._temperature.setValue(settings.temperature)\n self._max_tokens.setValue(settings.max_tokens)\n self._mods_dir.setText(settings.isaac_mod_dir or \"\")\n self._log_file.setText(settings.detected_log_file or \"\")\n self._rag_path.setText(settings.rag_kb_path)\n self._faiss_path.setText(settings.faiss_index_path)\n self._xml_cache.setText(settings.xml_schema_cache_path)\n self._on_provider_changed(self._provider_combo.currentText())\n\n def _on_provider_changed(self, provider: str):\n \"\"\"Show/hide groups based on selected provider.\"\"\"\n is_openai = provider in (\"openai\", \"deepseek\")\n self._openai_group.setVisible(is_openai)\n self._glm_group.setVisible(provider == \"glm\")\n\n def _auto_detect(self):\n \"\"\"Auto-detect Isaac paths and update fields.\"\"\"\n try:\n paths = resolve_all_paths()\n if paths.get(\"mods_dir\"):\n self._mods_dir.setText(str(paths[\"mods_dir\"]))\n if paths.get(\"log_file\"):\n self._log_file.setText(str(paths[\"log_file\"]))\n QMessageBox.information(self, \"Detection Complete\", f\"Found:\\nMods: {paths.get('mods_dir')}\\nLog: {paths.get('log_file')}\")\n except Exception as exc:\n QMessageBox.warning(self, \"Detection Failed\", str(exc))\n\n def _browse_dir(self, target: QLineEdit, title: str):\n path = QFileDialog.getExistingDirectory(self, title, target.text() or os.path.expanduser(\"~\"))\n if path:\n target.setText(path)\n\n def _browse_file(self, target: QLineEdit, title: str, filter_str: str):\n path, _ = QFileDialog.getOpenFileName(self, title, target.text() or os.path.expanduser(\"~\"), filter_str)\n if path:\n target.setText(path)\n\n def _save_settings(self):\n \"\"\"Write settings to .env file.\"\"\"\n env_path = Path(\".env\")\n env_lines = {}\n\n # Read existing .env\n if env_path.exists():\n for line in env_path.read_text().splitlines():\n line = line.strip()\n if \"=\" in line and not line.startswith(\"#\"):\n key, _, val = line.partition(\"=\")\n env_lines[key.strip()] = val.strip().strip('\"')\n\n # Update with current values\n updates = {\n \"LLM_PROVIDER\": self._provider_combo.currentText(),\n \"OPENAI_API_KEY\": self._openai_key.text() or \"\",\n \"OPENAI_MODEL\": self._openai_model.currentText(),\n \"GLM_API_KEY\": self._glm_key.text() or \"\",\n \"GLM_MODEL\": self._glm_model.currentText(),\n \"LLM_TEMPERATURE\": str(self._temperature.value()),\n \"LLM_MAX_TOKENS\": str(self._max_tokens.value()),\n \"ISAAC_MOD_DIR\": self._mods_dir.text() or \"./mods\",\n \"RAG_KB_PATH\": self._rag_path.text() or \"\",\n \"FAISS_INDEX_PATH\": self._faiss_path.text() or \"\",\n \"XML_SCHEMA_CACHE_PATH\": self._xml_cache.text() or \"\",\n }\n env_lines.update(updates)\n\n # Write .env\n content = \"\\n\".join(f'{k}=\"{v}\"' for k, v in env_lines.items() if v)\n env_path.write_text(content + \"\\n\")\n\n # Reload settings (in-process)\n for key, value in updates.items():\n field_name = key.lower()\n if hasattr(settings, field_name):\n setattr(settings, field_name, value)\n\n def _save_and_accept(self):\n self._save_settings()\n self.accept()\n"}}}}