Files
2026-09-09 18:56:03 +03:00

294 lines
12 KiB
Python

import time
import subprocess
import platform
import shutil
try:
import psutil
_PSUTIL = True
except ImportError:
_PSUTIL = False
_SYSTEM = platform.system()
_APP_ALIASES: dict[str, dict[str, str]] = {
"chrome": {"Windows": "chrome", "Darwin": "Google Chrome", "Linux": "google-chrome"},
"google chrome": {"Windows": "chrome", "Darwin": "Google Chrome", "Linux": "google-chrome"},
"firefox": {"Windows": "firefox", "Darwin": "Firefox", "Linux": "firefox"},
"edge": {"Windows": "msedge", "Darwin": "Microsoft Edge", "Linux": "microsoft-edge"},
"brave": {"Windows": "brave", "Darwin": "Brave Browser", "Linux": "brave-browser"},
"safari": {"Windows": "msedge", "Darwin": "Safari", "Linux": "firefox"},
"opera": {"Windows": "opera", "Darwin": "Opera", "Linux": "opera"},
"whatsapp": {"Windows": "WhatsApp", "Darwin": "WhatsApp", "Linux": "whatsapp"},
"telegram": {"Windows": "Telegram", "Darwin": "Telegram", "Linux": "telegram"},
"discord": {"Windows": "Discord", "Darwin": "Discord", "Linux": "discord"},
"slack": {"Windows": "Slack", "Darwin": "Slack", "Linux": "slack"},
"zoom": {"Windows": "Zoom", "Darwin": "zoom.us", "Linux": "zoom"},
"teams": {"Windows": "msteams", "Darwin": "Microsoft Teams", "Linux": "teams"},
"skype": {"Windows": "skype", "Darwin": "Skype", "Linux": "skype"},
"signal": {"Windows": "signal", "Darwin": "Signal", "Linux": "signal"},
"spotify": {"Windows": "Spotify", "Darwin": "Spotify", "Linux": "spotify"},
"vlc": {"Windows": "vlc", "Darwin": "VLC", "Linux": "vlc"},
"netflix": {"Windows": "Netflix", "Darwin": "Netflix", "Linux": "firefox"},
"vscode": {"Windows": "code", "Darwin": "Visual Studio Code", "Linux": "code"},
"visual studio code": {"Windows": "code", "Darwin": "Visual Studio Code", "Linux": "code"},
"code": {"Windows": "code", "Darwin": "Visual Studio Code", "Linux": "code"},
"terminal": {"Windows": "wt", "Darwin": "Terminal", "Linux": "x-terminal-emulator"},
"cmd": {"Windows": "cmd.exe", "Darwin": "Terminal", "Linux": "bash"},
"powershell": {"Windows": "powershell.exe", "Darwin": "Terminal", "Linux": "bash"},
"postman": {"Windows": "Postman", "Darwin": "Postman", "Linux": "postman"},
"git": {"Windows": "git-bash", "Darwin": "Terminal", "Linux": "bash"},
"figma": {"Windows": "Figma", "Darwin": "Figma", "Linux": "figma"},
"blender": {"Windows": "blender", "Darwin": "Blender", "Linux": "blender"},
"word": {"Windows": "winword", "Darwin": "Microsoft Word", "Linux": "libreoffice --writer"},
"excel": {"Windows": "excel", "Darwin": "Microsoft Excel", "Linux": "libreoffice --calc"},
"powerpoint": {"Windows": "powerpnt", "Darwin": "Microsoft PowerPoint", "Linux": "libreoffice --impress"},
"libreoffice": {"Windows": "soffice", "Darwin": "LibreOffice", "Linux": "libreoffice"},
"notepad": {"Windows": "notepad.exe", "Darwin": "TextEdit", "Linux": "gedit"},
"textedit": {"Windows": "notepad.exe", "Darwin": "TextEdit", "Linux": "gedit"},
"explorer": {"Windows": "explorer.exe", "Darwin": "Finder", "Linux": "nautilus"},
"file explorer": {"Windows": "explorer.exe", "Darwin": "Finder", "Linux": "nautilus"},
"finder": {"Windows": "explorer.exe", "Darwin": "Finder", "Linux": "nautilus"},
"task manager": {"Windows": "taskmgr.exe", "Darwin": "Activity Monitor", "Linux": "gnome-system-monitor"},
"settings": {"Windows": "ms-settings:", "Darwin": "System Preferences", "Linux": "gnome-control-center"},
"calculator": {"Windows": "calc.exe", "Darwin": "Calculator", "Linux": "gnome-calculator"},
"paint": {"Windows": "mspaint.exe", "Darwin": "Preview", "Linux": "gimp"},
"instagram": {"Windows": "Instagram", "Darwin": "Instagram", "Linux": "firefox"},
"tiktok": {"Windows": "TikTok", "Darwin": "TikTok", "Linux": "firefox"},
"notion": {"Windows": "Notion", "Darwin": "Notion", "Linux": "notion"},
"obsidian": {"Windows": "Obsidian", "Darwin": "Obsidian", "Linux": "obsidian"},
"capcut": {"Windows": "CapCut", "Darwin": "CapCut", "Linux": "capcut"},
"steam": {"Windows": "steam", "Darwin": "Steam", "Linux": "steam"},
"epic": {"Windows": "EpicGamesLauncher", "Darwin": "Epic Games Launcher", "Linux": "legendary"},
"epic games": {"Windows": "EpicGamesLauncher", "Darwin": "Epic Games Launcher", "Linux": "legendary"},
}
def _normalize(raw: str) -> str:
key = raw.lower().strip()
if key in _APP_ALIASES:
return _APP_ALIASES[key].get(_SYSTEM, raw)
for alias_key, os_map in _APP_ALIASES.items():
if alias_key in key or key in alias_key:
return os_map.get(_SYSTEM, raw)
return raw
def _launch_windows(app_name: str) -> bool:
if shutil.which(app_name) or shutil.which(app_name.split(".")[0]):
try:
subprocess.Popen(
app_name,
shell=True,
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
)
time.sleep(1.5)
return True
except Exception as e:
print(f"[open_app] subprocess failed: {e}")
if ":" in app_name:
try:
subprocess.Popen(f"start {app_name}", shell=True)
time.sleep(1.0)
return True
except Exception:
pass
try:
import pyautogui
pyautogui.PAUSE = 0.1
pyautogui.press("win")
time.sleep(0.7)
pyautogui.write(app_name, interval=0.05)
time.sleep(0.9)
pyautogui.press("enter")
time.sleep(2.5)
return True
except Exception as e:
print(f"[open_app] Start Menu search failed: {e}")
return False
def _launch_macos(app_name: str) -> bool:
try:
result = subprocess.run(
["open", "-a", app_name],
capture_output=True, timeout=8
)
if result.returncode == 0:
time.sleep(1.0)
return True
except Exception:
pass
try:
result = subprocess.run(
["open", "-a", f"{app_name}.app"],
capture_output=True, timeout=8
)
if result.returncode == 0:
time.sleep(1.0)
return True
except Exception:
pass
binary = shutil.which(app_name) or shutil.which(app_name.lower())
if binary:
try:
subprocess.Popen(
[binary],
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL
)
time.sleep(1.0)
return True
except Exception:
pass
try:
import pyautogui
pyautogui.hotkey("command", "space")
time.sleep(0.6)
pyautogui.write(app_name, interval=0.05)
time.sleep(0.8)
pyautogui.press("enter")
time.sleep(1.5)
return True
except Exception as e:
print(f"[open_app] Spotlight failed: {e}")
return False
_LINUX_TERMINAL_FALLBACKS = [
"x-terminal-emulator", "gnome-terminal", "konsole", "xfce4-terminal",
"xterm", "lxterminal", "mate-terminal", "tilix", "alacritty", "kitty",
]
def _launch_linux(app_name: str) -> bool:
# terminal emulators: try common ones in order
if app_name in ("x-terminal-emulator", "gnome-terminal", "terminal"):
for term in _LINUX_TERMINAL_FALLBACKS:
if shutil.which(term):
try:
subprocess.Popen([term], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
time.sleep(1.0)
return True
except Exception:
continue
binary = (
shutil.which(app_name) or
shutil.which(app_name.lower()) or
shutil.which(app_name.lower().replace(" ", "-")) or
shutil.which(app_name.lower().replace(" ", "_"))
)
if binary:
try:
subprocess.Popen(
[binary],
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL
)
time.sleep(1.0)
return True
except Exception:
pass
try:
subprocess.run(
["xdg-open", app_name],
capture_output=True, timeout=5
)
return True
except Exception:
pass
for desktop_name in [
app_name.lower(),
app_name.lower().replace(" ", "-"),
app_name.lower().replace(" ", ""),
]:
try:
result = subprocess.run(
["gtk-launch", desktop_name],
capture_output=True, timeout=5
)
if result.returncode == 0:
return True
except Exception:
pass
return False
_OS_LAUNCHERS = {
"Windows": _launch_windows,
"Darwin": _launch_macos,
"Linux": _launch_linux,
}
def open_app(
parameters=None,
response=None,
player=None,
session_memory=None,
) -> str:
app_name = (parameters or {}).get("app_name", "").strip()
if not app_name:
return "No application name provided."
launcher = _OS_LAUNCHERS.get(_SYSTEM)
if launcher is None:
return f"Unsupported operating system: {_SYSTEM}"
normalized = _normalize(app_name)
print(f"[open_app] Launching: '{app_name}' → '{normalized}' ({_SYSTEM})")
if player:
player.write_log(f"[open_app] {app_name}")
try:
if launcher(normalized):
return f"Opened {app_name}."
if normalized.lower() != app_name.lower():
if launcher(app_name):
return f"Opened {app_name}."
return (
f"Could not confirm that {app_name} launched. "
f"It may still be loading, or it might not be installed."
)
except Exception as e:
print(f"[open_app] Error: {e}")
return f"Failed to open {app_name}: {e}"
# ── Tool declaration (auto-discovered by core/action_loader.py) ──────────────
TOOL = {
"name": "open_app",
"description": "Opens any application on the computer. Use this whenever the user asks to open, launch, or start any app, website, or program. Always call this tool — never just say you opened it.",
"parameters": {
"type": "OBJECT",
"properties": {
"app_name": {
"type": "STRING",
"description": "Exact name of the application (e.g. 'WhatsApp', 'Chrome', 'Spotify')"
}
},
"required": [
"app_name"
]
},
"handler": open_app,
}