diff --git a/cli/commands/install.py b/cli/commands/install.py index b72bcba1..442694d3 100644 --- a/cli/commands/install.py +++ b/cli/commands/install.py @@ -78,12 +78,13 @@ def _is_china_network() -> bool: def _pip_install(package_spec: str, stream: StreamFn) -> int: - """Install a package, retrying with --user on permission failure.""" + """Install a package, preferring prebuilt wheels; retry with --user on perm error.""" python = sys.executable - ret = subprocess.call([python, "-m", "pip", "install", package_spec]) + base = [python, "-m", "pip", "install", "--prefer-binary"] + ret = subprocess.call(base + [package_spec]) if ret != 0: stream(" Retrying with --user flag...", "yellow") - ret = subprocess.call([python, "-m", "pip", "install", "--user", package_spec]) + ret = subprocess.call(base + ["--user", package_spec]) return ret @@ -155,6 +156,22 @@ def run_install_browser( target_version = PLAYWRIGHT_LEGACY_VERSION if legacy_mode else PLAYWRIGHT_VERSION + # Windows-only: greenlet 3.2.x ships no Windows wheel, so pip would build it + # from source (needs MSVC) and fail. Pre-install 3.1.x (has win wheels for + # py3.7-3.13) which still satisfies playwright's greenlet>=3.1.1,<4. + if sys.platform == "win32": + stream("[1/3] Pre-installing greenlet (prebuilt wheel) for Windows...", "yellow") + ret = subprocess.call( + [python, "-m", "pip", "install", "--only-binary=:all:", "greenlet>=3.1.1,<3.2"] + ) + if ret != 0: + stream( + " Could not pre-install a prebuilt greenlet wheel.\n" + " playwright may try to build greenlet from source, which needs\n" + " Microsoft C++ Build Tools: https://visualstudio.microsoft.com/visual-cpp-build-tools/", + "yellow", + ) + _phase(on_phase, _t("📦 [1/3] 正在安装 Playwright Python 包…", "📦 [1/3] Installing Playwright Python package…")) stream("[1/3] Installing playwright Python package...", "yellow") ret = _pip_install(f"playwright=={target_version}", stream) diff --git a/common/cloud_client.py b/common/cloud_client.py index b260c410..c66eecb5 100644 --- a/common/cloud_client.py +++ b/common/cloud_client.py @@ -172,6 +172,11 @@ class CloudClient(LinkAIClient): if key in available_setting and config.get(key) is not None: local_config[key] = config.get(key) + # Self-evolution switch: normalize remote value (bool / "Y"/"N" / "true") + # to a real bool so the evolution config parser reads it correctly. + if config.get("self_evolution_enabled") is not None: + local_config["self_evolution_enabled"] = self._to_bool(config.get("self_evolution_enabled")) + # Voice settings reply_voice_mode = config.get("reply_voice_mode") if reply_voice_mode: @@ -341,6 +346,20 @@ class CloudClient(LinkAIClient): except Exception as e: logger.warning(f"[CloudClient] Failed to remove weixin credentials: {e}") + # ------------------------------------------------------------------ + # value helpers + # ------------------------------------------------------------------ + @staticmethod + def _to_bool(value) -> bool: + """Normalize a remote config value to bool (bool / "Y"/"N" / "true"/"1").""" + if isinstance(value, bool): + return value + if isinstance(value, (int, float)): + return value != 0 + if isinstance(value, str): + return value.strip().lower() in ("y", "yes", "true", "1", "on") + return False + # ------------------------------------------------------------------ # channel credentials helpers # ------------------------------------------------------------------ @@ -855,6 +874,10 @@ def _build_config(): "agent_max_context_turns": local_conf.get("agent_max_context_turns"), "agent_max_context_tokens": local_conf.get("agent_max_context_tokens"), "agent_max_steps": local_conf.get("agent_max_steps"), + # Self-evolution switch reported so the cloud console can reflect state + "self_evolution_enabled": "Y" if local_conf.get("self_evolution_enabled") else "N", + "self_evolution_idle_minutes": local_conf.get("self_evolution_idle_minutes"), + "self_evolution_min_turns": local_conf.get("self_evolution_min_turns"), "channelType": local_conf.get("channel_type"), } diff --git a/run.sh b/run.sh index bfe45630..769273b5 100755 --- a/run.sh +++ b/run.sh @@ -980,7 +980,10 @@ start_project() { echo -e " ${GREEN}./run.sh status${NC} $(t "查看状态" "Check status")" echo -e " ${GREEN}./run.sh logs${NC} $(t "查看日志" "View logs")" echo -e " ${GREEN}./run.sh update${NC} $(t "更新并重启" "Update and restart")" + echo -e " ${GREEN}cow install-browser${NC} $(t "安装浏览器工具" "Install browser tool")" fi + echo "" + echo -e "${YELLOW}$(t "提示:需要让 Agent 浏览网页时,运行 cow install-browser 安装浏览器工具" "Tip: to let the Agent browse the web, run 'cow install-browser' to install the browser tool")${NC}" echo -e "${CYAN}${BOLD}=========================================${NC}" echo "" diff --git a/scripts/run.ps1 b/scripts/run.ps1 index a9a0673e..5b6c1daa 100644 --- a/scripts/run.ps1 +++ b/scripts/run.ps1 @@ -748,6 +748,7 @@ function Install-Mode { # Auto-start after configuration for a true out-of-the-box experience. Write-Host "" if ($script:AccessInfo) { Write-Cow $script:AccessInfo } + Write-Warn (T "提示:需要让 Agent 浏览网页时,运行 cow install-browser 安装浏览器工具" "Tip: to let the Agent browse the web, run 'cow install-browser' to install the browser tool") Start-CowAgent }