Skip to content

Commit def088f

Browse files
Merge pull request #221 from askui/integrate-new-tools-from-core
Integrate new tools from core
2 parents 86a6639 + 9f89e63 commit def088f

38 files changed

Lines changed: 2547 additions & 444 deletions

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ typecheck = "mypy"
7474
"lint:fix",
7575
] }
7676
"grpc:gen" = "bash scripts/grpc-gen.sh"
77-
"json:gen" = "datamodel-codegen --output-model-type pydantic_v2.BaseModel --input src/askui/tools/askui/askui_ui_controller_grpc/json_schema/ --input-file-type jsonschema --output src/askui/tools/askui/askui_ui_controller_grpc/generated/"
77+
"json:gen" = "datamodel-codegen --output-model-type pydantic_v2.BaseModel --input src/askui/tools/askui/askui_ui_controller_grpc/json_schema/ --input-file-type jsonschema --output src/askui/tools/askui/askui_ui_controller_grpc/generated/ --use-title-as-name "
7878

7979
[dependency-groups]
8080
dev = [

src/askui/agent.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
)
1414
from askui.tools.computer import (
1515
ComputerGetMousePositionTool,
16+
ComputerGetSystemInfoTool,
1617
ComputerKeyboardPressedTool,
1718
ComputerKeyboardReleaseTool,
1819
ComputerKeyboardTapTool,
@@ -92,6 +93,7 @@ def __init__(
9293
models=models,
9394
tools=[
9495
ExceptionTool(),
96+
ComputerGetSystemInfoTool(),
9597
ComputerGetMousePositionTool(),
9698
ComputerKeyboardPressedTool(),
9799
ComputerKeyboardReleaseTool(),

src/askui/agent_base.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ def __init__(
106106
)
107107

108108
self.act_tool_collection = ToolCollection(tools=tools)
109+
self.act_tool_collection.add_agent_os(agent_os)
109110

110111
self.act_settings = ActSettings()
111112
self.caching_settings = CachingSettings()

src/askui/models/anthropic/messages_api.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ def create_message(
7474

7575
response = self._client.beta.messages.create( # type: ignore[misc]
7676
messages=_messages,
77-
max_tokens=max_tokens or 4096,
77+
max_tokens=max_tokens or 8192,
7878
model=model,
7979
tools=tools.to_params() if not isinstance(tools, Omit) else omit,
8080
betas=betas,

src/askui/models/shared/android_base_tool.py

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from askui.models.shared.tool_tags import ToolTags
44
from askui.models.shared.tools import ToolWithAgentOS
55
from askui.tools import AgentOs
6+
from askui.tools.agent_os_type_error import AgentOsTypeError
67
from askui.tools.android.agent_os import AndroidAgentOs
78

89

@@ -33,12 +34,10 @@ def agent_os(self) -> AndroidAgentOs:
3334
"""
3435
agent_os = super().agent_os
3536
if not isinstance(agent_os, AndroidAgentOs):
36-
msg = (
37-
"Agent OS is not an AndroidAgentOs. "
38-
"Call `agent_os = ...` or initialize the tool with an "
39-
"AndroidAgentOs."
37+
raise AgentOsTypeError(
38+
expected_type=AndroidAgentOs,
39+
actual_type=type(agent_os),
4040
)
41-
raise TypeError(msg)
4241
return agent_os
4342

4443
@agent_os.setter
@@ -52,9 +51,8 @@ def agent_os(self, agent_os: AgentOs | AndroidAgentOs) -> None:
5251
TypeError: If the agent OS is not an AndroidAgentOs instance.
5352
"""
5453
if not isinstance(agent_os, AndroidAgentOs):
55-
msg = (
56-
"Agent OS must be an AndroidAgentOs instance. "
57-
f"Got {type(agent_os).__name__} instead."
54+
raise AgentOsTypeError(
55+
expected_type=AndroidAgentOs,
56+
actual_type=type(agent_os),
5857
)
59-
raise TypeError(msg)
6058
self._agent_os = agent_os

src/askui/models/shared/computer_base_tool.py

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from askui.models.shared.tool_tags import ToolTags
44
from askui.models.shared.tools import ToolWithAgentOS
55
from askui.tools.agent_os import AgentOs
6+
from askui.tools.agent_os_type_error import AgentOsTypeError
67
from askui.tools.android.agent_os import AndroidAgentOs
78

89

@@ -30,12 +31,10 @@ def agent_os(self) -> AgentOs:
3031
"""
3132
agent_os = super().agent_os
3233
if not isinstance(agent_os, AgentOs):
33-
msg = (
34-
"Agent OS is not a ComputerAgentOs. "
35-
"Call `agent_os = ...` or initialize the tool with a "
36-
"ComputerAgentOs."
34+
raise AgentOsTypeError(
35+
expected_type=AgentOs,
36+
actual_type=type(agent_os),
3737
)
38-
raise TypeError(msg)
3938
return agent_os
4039

4140
@agent_os.setter
@@ -49,9 +48,8 @@ def agent_os(self, agent_os: AgentOs | AndroidAgentOs) -> None:
4948
TypeError: If the agent OS is not an AgentOs instance.
5049
"""
5150
if not isinstance(agent_os, AgentOs):
52-
msg = (
53-
"Agent OS must be an AgentOs instance. "
54-
f"Got {type(agent_os).__name__} instead."
51+
raise AgentOsTypeError(
52+
expected_type=AgentOs,
53+
actual_type=type(agent_os),
5554
)
56-
raise TypeError(msg)
5755
self._agent_os = agent_os

src/askui/models/shared/settings.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ class MessageSettings(BaseModel):
1919
model_config = ConfigDict(arbitrary_types_allowed=True)
2020

2121
betas: list[AnthropicBetaParam] | Omit = omit
22-
max_tokens: int = 4096
22+
max_tokens: int = 8192
2323
system: ActSystemPrompt | None = None
2424
thinking: BetaThinkingConfigParam | Omit = omit
2525
tool_choice: BetaToolChoiceParam | Omit = omit

src/askui/models/shared/tools.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -473,12 +473,13 @@ def _run_regular_tool(
473473
except AgentException:
474474
raise
475475
except Exception as e: # noqa: BLE001
476+
error_message = getattr(e, "message", str(e))
476477
logger.warning(
477478
"Tool failed",
478-
extra={"tool_name": tool_use_block_param.name, "error": str(e)},
479+
extra={"tool_name": tool_use_block_param.name, "error": error_message},
479480
)
480481
return ToolResultBlockParam(
481-
content=str(e),
482+
content=f"Tool raised an unexpected error: {error_message}",
482483
is_error=True,
483484
tool_use_id=tool_use_block_param.id,
484485
)

src/askui/tools/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from .agent_os import AgentOs, Coordinate, ModifierKey, PcKey
2-
from .askui.command_helpers import create_style
2+
from .askui.askui_controller import RenderObjectStyle
33
from .computer_agent_os_facade import ComputerAgentOsFacade
44
from .toolbox import AgentToolbox
55

@@ -9,6 +9,6 @@
99
"ModifierKey",
1010
"PcKey",
1111
"Coordinate",
12-
"create_style",
12+
"RenderObjectStyle",
1313
"ComputerAgentOsFacade",
1414
]

src/askui/tools/agent_os.py

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,17 @@
77
from askui.models.shared.tool_tags import ToolTags
88

99
if TYPE_CHECKING:
10+
from askui.tools.askui.askui_ui_controller_grpc.generated import (
11+
Controller_V1_pb2 as controller_v1_pbs,
12+
)
1013
from askui.tools.askui.askui_ui_controller_grpc.generated.AgentOS_Send_Request_2501 import ( # noqa: E501
1114
RenderObjectStyle,
1215
)
16+
from askui.tools.askui.askui_ui_controller_grpc.generated.AgentOS_Send_Response_2501 import ( # noqa: E501
17+
GetActiveProcessResponseModel,
18+
GetActiveWindowResponseModel,
19+
GetSystemInfoResponseModel,
20+
)
1321

1422
MouseButton = Literal["left", "middle", "right"]
1523

@@ -175,12 +183,16 @@ class Display(BaseModel):
175183
)
176184

177185
id: int = Field(validation_alias="displayID")
186+
name: str = Field(validation_alias="name")
178187
size: DisplaySize = Field(validation_alias="sizeInPixels")
179188

180189

181190
class DisplaysListResponse(BaseModel):
182191
data: list[Display] = Field(validation_alias="displays")
183192

193+
def __str__(self) -> str:
194+
return ",".join([str(display) for display in self.data])
195+
184196

185197
InputEvent = ClickEvent
186198

@@ -529,3 +541,121 @@ def clear_render_objects(self) -> None:
529541
Response confirming the clearing.
530542
"""
531543
raise NotImplementedError
544+
545+
def get_process_list(
546+
self, get_extended_info: bool = False
547+
) -> "controller_v1_pbs.Response_GetProcessList":
548+
"""
549+
Get a list of running processes.
550+
551+
Args:
552+
get_extended_info (bool, optional): Whether to include
553+
extended process information.
554+
Defaults to `False`.
555+
556+
Returns:
557+
controller_v1_pbs.Response_GetProcessList: Process list response containing:
558+
- processes: List of ProcessInfo objects
559+
"""
560+
raise NotImplementedError
561+
562+
def get_window_list(
563+
self, process_id: int
564+
) -> "controller_v1_pbs.Response_GetWindowList":
565+
"""
566+
Get a list of windows for a specific process.
567+
568+
Args:
569+
process_id (int): The ID of the process to get windows for.
570+
571+
Returns:
572+
controller_v1_pbs.Response_GetWindowList: Window list response containing:
573+
- windows: List of WindowInfo objects with ID and name
574+
"""
575+
raise NotImplementedError
576+
577+
def set_mouse_delay(self, delay_ms: int) -> None:
578+
"""
579+
Configure mouse action delay.
580+
581+
Args:
582+
delay_ms (int): The delay in milliseconds to set for mouse actions.
583+
"""
584+
raise NotImplementedError
585+
586+
def set_keyboard_delay(self, delay_ms: int) -> None:
587+
"""
588+
Configure keyboard action delay.
589+
590+
Args:
591+
delay_ms (int): The delay in milliseconds to set for keyboard actions.
592+
"""
593+
raise NotImplementedError
594+
595+
def set_active_window(self, process_id: int, window_id: int) -> int:
596+
"""
597+
Set the active window for automation.
598+
Adds the window as a virtual display and returns the display ID.
599+
It raises an error if display length is not increased after adding the window.
600+
601+
Args:
602+
process_id (int): The ID of the process that owns the window.
603+
window_id (int): The ID of the window to set as active.
604+
605+
Returns:
606+
int: The new Display ID.
607+
608+
Raises:
609+
AskUiControllerError:
610+
If display length is not increased after adding the window.
611+
"""
612+
raise NotImplementedError
613+
614+
def get_system_info(self) -> "GetSystemInfoResponseModel":
615+
"""
616+
Get the system information.
617+
618+
Returns:
619+
GetSystemInfoResponseModel: The system information.
620+
"""
621+
raise NotImplementedError
622+
623+
def get_active_process(self) -> "GetActiveProcessResponseModel":
624+
"""
625+
Get the active process.
626+
627+
Returns:
628+
GetActiveProcessResponseModel: The active process.
629+
"""
630+
raise NotImplementedError
631+
632+
def set_active_process(self, process_id: int) -> None:
633+
"""
634+
Set the active process.
635+
636+
Args:
637+
process_id (int): The ID of the process to set as active.
638+
"""
639+
raise NotImplementedError
640+
641+
def get_active_window(self) -> "GetActiveWindowResponseModel":
642+
"""
643+
Gets the window id and name in addition to the process id
644+
and name of the currently active window (in focus).
645+
646+
Returns:
647+
GetActiveWindowResponseModel: The active window.
648+
"""
649+
raise NotImplementedError
650+
651+
def set_window_in_focus(self, process_id: int, window_id: int) -> None:
652+
"""
653+
Sets the window with the specified windowId of the process
654+
with the specified processId active,
655+
which brings it to the front and gives it focus.
656+
657+
Args:
658+
process_id (int): The ID of the process that owns the window.
659+
window_id (int): The ID of the window to set as active.
660+
"""
661+
raise NotImplementedError

0 commit comments

Comments
 (0)