88
99import grpc
1010from PIL import Image
11- from pydantic import BaseModel , Field , model_validator
12- from pydantic_settings import BaseSettings , SettingsConfigDict
1311from typing_extensions import Self , override
1412
1513from askui .container import telemetry
1614from askui .logger import logger
1715from askui .reporting import Reporter
1816from askui .tools .agent_os import AgentOs , Coordinate , ModifierKey , PcKey
17+ from askui .tools .askui .askui_controller_settings import AskUiControllerSettings
1918from askui .tools .askui .askui_ui_controller_grpc .generated import (
2019 Controller_V1_pb2 as controller_v1_pbs ,
2120)
4847)
4948
5049
51- class RemoteDeviceController (BaseModel ):
52- askui_remote_device_controller : pathlib .Path = Field (
53- alias = "AskUIRemoteDeviceController"
54- )
55-
56-
57- class Executables (BaseModel ):
58- executables : RemoteDeviceController = Field (alias = "Executables" )
59-
60-
61- class InstalledPackages (BaseModel ):
62- remote_device_controller_uuid : Executables = Field (
63- alias = "{aed1b543-e856-43ad-b1bc-19365d35c33e}"
64- )
65-
66-
67- class AskUiComponentRegistry (BaseModel ):
68- definition_version : int = Field (alias = "DefinitionVersion" )
69- installed_packages : InstalledPackages = Field (alias = "InstalledPackages" )
70-
71-
72- class AskUiControllerSettings (BaseSettings ):
73- model_config = SettingsConfigDict (
74- env_prefix = "ASKUI_" ,
75- )
76-
77- component_registry_file : pathlib .Path | None = None
78- installation_directory : pathlib .Path | None = None
79-
80- @model_validator (mode = "after" )
81- def validate_either_component_registry_or_installation_directory_is_set (
82- self ,
83- ) -> "AskUiControllerSettings" :
84- if self .component_registry_file is None and self .installation_directory is None :
85- error_msg = (
86- "Either ASKUI_COMPONENT_REGISTRY_FILE or "
87- "ASKUI_INSTALLATION_DIRECTORY environment variable must be set"
88- )
89- raise ValueError (error_msg )
90- return self
91-
92-
9350class AskUiControllerServer :
9451 """
9552 Concrete implementation of `ControllerServer` for managing the AskUI Remote Device
9653 Controller process.
9754 Handles process discovery, startup, and shutdown for the native controller binary.
55+
56+ Args:
57+ settings (AskUiControllerSettings | None, optional): Settings for the AskUI.
9858 """
9959
100- def __init__ (self ) -> None :
60+ def __init__ (self , settings : AskUiControllerSettings | None = None ) -> None :
10161 self ._process : subprocess .Popen [bytes ] | None = None
102- self ._settings = AskUiControllerSettings ()
103-
104- def _find_remote_device_controller (self ) -> pathlib .Path :
105- if (
106- self ._settings .installation_directory is not None
107- and self ._settings .component_registry_file is None
108- ):
109- logger .warning (
110- "Outdated AskUI Suite detected. Please update to the latest version."
111- )
112- askui_remote_device_controller_path = (
113- self ._find_remote_device_controller_by_legacy_path ()
114- )
115- if not askui_remote_device_controller_path .is_file ():
116- error_msg = (
117- "AskUIRemoteDeviceController executable does not exist under "
118- f"'{ askui_remote_device_controller_path } '"
119- )
120- raise FileNotFoundError (error_msg )
121- return askui_remote_device_controller_path
122- return self ._find_remote_device_controller_by_component_registry ()
123-
124- def _find_remote_device_controller_by_component_registry (self ) -> pathlib .Path :
125- assert self ._settings .component_registry_file is not None , (
126- "Component registry file is not set"
127- )
128- component_registry = AskUiComponentRegistry .model_validate_json (
129- self ._settings .component_registry_file .read_text ()
130- )
131- askui_remote_device_controller_path = (
132- component_registry .installed_packages .remote_device_controller_uuid .executables .askui_remote_device_controller # noqa: E501
133- )
134- if not askui_remote_device_controller_path .is_file ():
135- error_msg = (
136- "AskUIRemoteDeviceController executable does not exist under "
137- f"'{ askui_remote_device_controller_path } '"
138- )
139- raise FileNotFoundError (error_msg )
140- return askui_remote_device_controller_path
141-
142- def _find_remote_device_controller_by_legacy_path (self ) -> pathlib .Path :
143- assert self ._settings .installation_directory is not None , (
144- "Installation directory is not set"
145- )
146- match sys .platform :
147- case "win32" :
148- return (
149- self ._settings .installation_directory
150- / "Binaries"
151- / "resources"
152- / "assets"
153- / "binaries"
154- / "AskuiRemoteDeviceController.exe"
155- )
156- case "darwin" :
157- return (
158- self ._settings .installation_directory
159- / "Binaries"
160- / "askui-ui-controller.app"
161- / "Contents"
162- / "Resources"
163- / "assets"
164- / "binaries"
165- / "AskuiRemoteDeviceController"
166- )
167- case "linux" :
168- return (
169- self ._settings .installation_directory
170- / "Binaries"
171- / "resources"
172- / "assets"
173- / "binaries"
174- / "AskuiRemoteDeviceController"
175- )
176- case _:
177- error_msg = (
178- f"Platform { sys .platform } not supported by "
179- "AskUI Remote Device Controller"
180- )
181- raise NotImplementedError (error_msg )
62+ self ._settings = settings or AskUiControllerSettings ()
18263
18364 def _start_process (self , path : pathlib .Path ) -> None :
18465 self ._process = subprocess .Popen (path )
@@ -198,11 +79,11 @@ def start(self, clean_up: bool = False) -> None:
19879 and process_exists ("AskuiRemoteDeviceController.exe" )
19980 ):
20081 self .clean_up ()
201- remote_device_controller_path = self ._find_remote_device_controller ()
20282 logger .debug (
203- "Starting AskUI Remote Device Controller: %s" , remote_device_controller_path
83+ "Starting AskUI Remote Device Controller: %s" ,
84+ self ._settings .controller_path ,
20485 )
205- self ._start_process (remote_device_controller_path )
86+ self ._start_process (self . _settings . controller_path )
20687 time .sleep (0.5 )
20788
20889 def clean_up (self ) -> None :
0 commit comments