Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions examples/print_app_tree.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from mlx_use.mac.tree import MacUITreeBuilder
from mlx_use.controller.service import Controller
from mlx_use.controller.service import Controller, _find_best_running_app
from mlx_use.controller.views import OpenAppAction
from mlx_use.agent.views import ActionModel

Expand Down Expand Up @@ -38,13 +38,13 @@ async def print_app_tree(app_name: str):

# Find the app's PID
app_pid = None
for app in workspace.runningApplications():
if app.bundleIdentifier() and bundle_id.lower() in app.bundleIdentifier().lower():
print(f'Found {formatted_app_name}!')
print(f'Bundle ID: {app.bundleIdentifier()}')
app_pid = app.processIdentifier()
print(f'PID: {app_pid}')
break
best_app = _find_best_running_app(workspace, formatted_app_name)
if best_app is not None:
print(f'Found {formatted_app_name}!')
print(f'Localized name: {best_app.localizedName()}')
print(f'Bundle ID: {best_app.bundleIdentifier()}')
app_pid = best_app.processIdentifier()
print(f'PID: {app_pid}')

if not app_pid:
print(f'❌ Could not find {formatted_app_name} app')
Expand Down
56 changes: 50 additions & 6 deletions mlx_use/controller/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,50 @@
import Cocoa
from playwright.async_api import Page


def _score_running_app(app, app_name: str) -> int:
"""Prefer the real app process over helper/background processes."""
name = (str(app.localizedName() or '')).lower()
bundle_id = (str(app.bundleIdentifier() or '')).lower()
target = app_name.lower()
score = 0

if name == target:
score += 100
elif target in name:
score += 40

if bundle_id == f'com.apple.{target}':
score += 120
elif bundle_id.endswith(f'.{target}'):
score += 80
elif target in bundle_id:
score += 20

if 'helper' in name or 'helper' in bundle_id:
score -= 200
if 'platformsupport' in name or 'platformsupport' in bundle_id:
score -= 200
if 'web content' in name or 'webcontent' in bundle_id:
score -= 120

return score


def _find_best_running_app(workspace, app_name: str):
apps = list(workspace.runningApplications())
scored = []
for app in apps:
try:
scored.append((_score_running_app(app, app_name), app))
except Exception:
continue
if not scored:
return None
scored.sort(key=lambda item: item[0], reverse=True)
best_score, best_app = scored[0]
return best_app if best_score > 0 else None
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai bot Mar 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: When scored selection returns None, fallback pgrep picks the first matching PID without helper/background filtering, reintroducing wrong app PID selection.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At mlx_use/controller/service.py, line 52:

<comment>When scored selection returns `None`, fallback `pgrep` picks the first matching PID without helper/background filtering, reintroducing wrong app PID selection.</comment>

<file context>
@@ -7,6 +7,50 @@
+		return None
+	scored.sort(key=lambda item: item[0], reverse=True)
+	best_score, best_app = scored[0]
+	return best_app if best_score > 0 else None
+
 from mlx_use.agent.views import ActionModel, ActionResult
</file context>
Fix with Cubic


from mlx_use.agent.views import ActionModel, ActionResult
from mlx_use.controller.registry.service import Registry
from mlx_use.controller.views import (
Expand Down Expand Up @@ -188,12 +232,12 @@ async def open_app(app_name: str):

await asyncio.sleep(1) # Give it a moment to appear in running apps
pid = None
for app in workspace.runningApplications():
if app.bundleIdentifier() and app_name.lower() in app.bundleIdentifier().lower():
logging.debug(f'Bundle ID: {app.bundleIdentifier()}')
pid = app.processIdentifier()
logging.debug(f'PID: {pid}')
break
best_app = _find_best_running_app(workspace, app_name)
if best_app is not None:
logging.debug(f'Localized name: {best_app.localizedName()}')
logging.debug(f'Bundle ID: {best_app.bundleIdentifier()}')
pid = best_app.processIdentifier()
logging.debug(f'PID: {pid}')

# If no PID is found, try to find the app by name with pgrep -i
if pid is None:
Expand Down