cua-agent 0.3.2__py3-none-any.whl → 0.4.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of cua-agent might be problematic. Click here for more details.
- agent/__init__.py +21 -12
- agent/__main__.py +21 -0
- agent/adapters/__init__.py +9 -0
- agent/adapters/huggingfacelocal_adapter.py +229 -0
- agent/agent.py +594 -0
- agent/callbacks/__init__.py +19 -0
- agent/callbacks/base.py +153 -0
- agent/callbacks/budget_manager.py +44 -0
- agent/callbacks/image_retention.py +139 -0
- agent/callbacks/logging.py +247 -0
- agent/callbacks/pii_anonymization.py +259 -0
- agent/callbacks/telemetry.py +210 -0
- agent/callbacks/trajectory_saver.py +305 -0
- agent/cli.py +297 -0
- agent/computer_handler.py +107 -0
- agent/decorators.py +90 -0
- agent/loops/__init__.py +11 -0
- agent/loops/anthropic.py +728 -0
- agent/loops/omniparser.py +339 -0
- agent/loops/openai.py +95 -0
- agent/loops/uitars.py +688 -0
- agent/responses.py +207 -0
- agent/telemetry.py +135 -14
- agent/types.py +79 -0
- agent/ui/__init__.py +7 -1
- agent/ui/__main__.py +2 -13
- agent/ui/gradio/__init__.py +6 -19
- agent/ui/gradio/app.py +94 -1313
- agent/ui/gradio/ui_components.py +721 -0
- cua_agent-0.4.0.dist-info/METADATA +424 -0
- cua_agent-0.4.0.dist-info/RECORD +33 -0
- agent/core/__init__.py +0 -27
- agent/core/agent.py +0 -210
- agent/core/base.py +0 -217
- agent/core/callbacks.py +0 -200
- agent/core/experiment.py +0 -249
- agent/core/factory.py +0 -122
- agent/core/messages.py +0 -332
- agent/core/provider_config.py +0 -21
- agent/core/telemetry.py +0 -142
- agent/core/tools/__init__.py +0 -21
- agent/core/tools/base.py +0 -74
- agent/core/tools/bash.py +0 -52
- agent/core/tools/collection.py +0 -46
- agent/core/tools/computer.py +0 -113
- agent/core/tools/edit.py +0 -67
- agent/core/tools/manager.py +0 -56
- agent/core/tools.py +0 -32
- agent/core/types.py +0 -88
- agent/core/visualization.py +0 -197
- agent/providers/__init__.py +0 -4
- agent/providers/anthropic/__init__.py +0 -6
- agent/providers/anthropic/api/client.py +0 -360
- agent/providers/anthropic/api/logging.py +0 -150
- agent/providers/anthropic/api_handler.py +0 -140
- agent/providers/anthropic/callbacks/__init__.py +0 -5
- agent/providers/anthropic/callbacks/manager.py +0 -65
- agent/providers/anthropic/loop.py +0 -568
- agent/providers/anthropic/prompts.py +0 -23
- agent/providers/anthropic/response_handler.py +0 -226
- agent/providers/anthropic/tools/__init__.py +0 -33
- agent/providers/anthropic/tools/base.py +0 -88
- agent/providers/anthropic/tools/bash.py +0 -66
- agent/providers/anthropic/tools/collection.py +0 -34
- agent/providers/anthropic/tools/computer.py +0 -396
- agent/providers/anthropic/tools/edit.py +0 -326
- agent/providers/anthropic/tools/manager.py +0 -54
- agent/providers/anthropic/tools/run.py +0 -42
- agent/providers/anthropic/types.py +0 -16
- agent/providers/anthropic/utils.py +0 -381
- agent/providers/omni/__init__.py +0 -8
- agent/providers/omni/api_handler.py +0 -42
- agent/providers/omni/clients/anthropic.py +0 -103
- agent/providers/omni/clients/base.py +0 -35
- agent/providers/omni/clients/oaicompat.py +0 -195
- agent/providers/omni/clients/ollama.py +0 -122
- agent/providers/omni/clients/openai.py +0 -155
- agent/providers/omni/clients/utils.py +0 -25
- agent/providers/omni/image_utils.py +0 -34
- agent/providers/omni/loop.py +0 -990
- agent/providers/omni/parser.py +0 -307
- agent/providers/omni/prompts.py +0 -64
- agent/providers/omni/tools/__init__.py +0 -30
- agent/providers/omni/tools/base.py +0 -29
- agent/providers/omni/tools/bash.py +0 -74
- agent/providers/omni/tools/computer.py +0 -179
- agent/providers/omni/tools/manager.py +0 -61
- agent/providers/omni/utils.py +0 -236
- agent/providers/openai/__init__.py +0 -6
- agent/providers/openai/api_handler.py +0 -456
- agent/providers/openai/loop.py +0 -472
- agent/providers/openai/response_handler.py +0 -205
- agent/providers/openai/tools/__init__.py +0 -15
- agent/providers/openai/tools/base.py +0 -79
- agent/providers/openai/tools/computer.py +0 -326
- agent/providers/openai/tools/manager.py +0 -106
- agent/providers/openai/types.py +0 -36
- agent/providers/openai/utils.py +0 -98
- agent/providers/uitars/__init__.py +0 -1
- agent/providers/uitars/clients/base.py +0 -35
- agent/providers/uitars/clients/mlxvlm.py +0 -263
- agent/providers/uitars/clients/oaicompat.py +0 -214
- agent/providers/uitars/loop.py +0 -660
- agent/providers/uitars/prompts.py +0 -63
- agent/providers/uitars/tools/__init__.py +0 -1
- agent/providers/uitars/tools/computer.py +0 -283
- agent/providers/uitars/tools/manager.py +0 -60
- agent/providers/uitars/utils.py +0 -264
- cua_agent-0.3.2.dist-info/METADATA +0 -295
- cua_agent-0.3.2.dist-info/RECORD +0 -87
- {cua_agent-0.3.2.dist-info → cua_agent-0.4.0.dist-info}/WHEEL +0 -0
- {cua_agent-0.3.2.dist-info → cua_agent-0.4.0.dist-info}/entry_points.txt +0 -0
agent/responses.py
ADDED
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Functions for making various Responses API items from different types of responses.
|
|
3
|
+
Based on the OpenAI spec for Responses API items.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import base64
|
|
7
|
+
import json
|
|
8
|
+
import uuid
|
|
9
|
+
from typing import List, Dict, Any, Literal, Union, Optional
|
|
10
|
+
|
|
11
|
+
from openai.types.responses.response_computer_tool_call_param import (
|
|
12
|
+
ResponseComputerToolCallParam,
|
|
13
|
+
ActionClick,
|
|
14
|
+
ActionDoubleClick,
|
|
15
|
+
ActionDrag,
|
|
16
|
+
ActionDragPath,
|
|
17
|
+
ActionKeypress,
|
|
18
|
+
ActionMove,
|
|
19
|
+
ActionScreenshot,
|
|
20
|
+
ActionScroll,
|
|
21
|
+
ActionType as ActionTypeAction,
|
|
22
|
+
ActionWait,
|
|
23
|
+
PendingSafetyCheck
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
from openai.types.responses.response_function_tool_call_param import ResponseFunctionToolCallParam
|
|
27
|
+
from openai.types.responses.response_output_text_param import ResponseOutputTextParam
|
|
28
|
+
from openai.types.responses.response_reasoning_item_param import ResponseReasoningItemParam, Summary
|
|
29
|
+
from openai.types.responses.response_output_message_param import ResponseOutputMessageParam
|
|
30
|
+
from openai.types.responses.easy_input_message_param import EasyInputMessageParam
|
|
31
|
+
from openai.types.responses.response_input_image_param import ResponseInputImageParam
|
|
32
|
+
|
|
33
|
+
def random_id():
|
|
34
|
+
return str(uuid.uuid4())
|
|
35
|
+
|
|
36
|
+
# User message items
|
|
37
|
+
def make_input_image_item(image_data: Union[str, bytes]) -> EasyInputMessageParam:
|
|
38
|
+
return EasyInputMessageParam(
|
|
39
|
+
content=[
|
|
40
|
+
ResponseInputImageParam(
|
|
41
|
+
type="input_image",
|
|
42
|
+
image_url=f"data:image/png;base64,{base64.b64encode(image_data).decode('utf-8') if isinstance(image_data, bytes) else image_data}"
|
|
43
|
+
)
|
|
44
|
+
],
|
|
45
|
+
role="user",
|
|
46
|
+
type="message"
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
# Text items
|
|
50
|
+
def make_reasoning_item(reasoning: str) -> ResponseReasoningItemParam:
|
|
51
|
+
return ResponseReasoningItemParam(
|
|
52
|
+
id=random_id(),
|
|
53
|
+
summary=[
|
|
54
|
+
Summary(text=reasoning, type="summary_text")
|
|
55
|
+
],
|
|
56
|
+
type="reasoning"
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
def make_output_text_item(content: str) -> ResponseOutputMessageParam:
|
|
60
|
+
return ResponseOutputMessageParam(
|
|
61
|
+
id=random_id(),
|
|
62
|
+
content=[
|
|
63
|
+
ResponseOutputTextParam(
|
|
64
|
+
text=content,
|
|
65
|
+
type="output_text",
|
|
66
|
+
annotations=[]
|
|
67
|
+
)
|
|
68
|
+
],
|
|
69
|
+
role="assistant",
|
|
70
|
+
status="completed",
|
|
71
|
+
type="message"
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
# Function call items
|
|
75
|
+
def make_function_call_item(function_name: str, arguments: Dict[str, Any], call_id: Optional[str] = None) -> ResponseFunctionToolCallParam:
|
|
76
|
+
return ResponseFunctionToolCallParam(
|
|
77
|
+
id=random_id(),
|
|
78
|
+
call_id=call_id if call_id else random_id(),
|
|
79
|
+
name=function_name,
|
|
80
|
+
arguments=json.dumps(arguments),
|
|
81
|
+
status="completed",
|
|
82
|
+
type="function_call"
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
# Computer tool call items
|
|
86
|
+
def make_click_item(x: int, y: int, button: Literal["left", "right", "wheel", "back", "forward"] = "left", call_id: Optional[str] = None) -> ResponseComputerToolCallParam:
|
|
87
|
+
return ResponseComputerToolCallParam(
|
|
88
|
+
id=random_id(),
|
|
89
|
+
call_id=call_id if call_id else random_id(),
|
|
90
|
+
action=ActionClick(
|
|
91
|
+
button=button,
|
|
92
|
+
type="click",
|
|
93
|
+
x=x,
|
|
94
|
+
y=y
|
|
95
|
+
),
|
|
96
|
+
pending_safety_checks=[],
|
|
97
|
+
status="completed",
|
|
98
|
+
type="computer_call"
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
def make_double_click_item(x: int, y: int, call_id: Optional[str] = None) -> ResponseComputerToolCallParam:
|
|
102
|
+
return ResponseComputerToolCallParam(
|
|
103
|
+
id=random_id(),
|
|
104
|
+
call_id=call_id if call_id else random_id(),
|
|
105
|
+
action=ActionDoubleClick(
|
|
106
|
+
type="double_click",
|
|
107
|
+
x=x,
|
|
108
|
+
y=y
|
|
109
|
+
),
|
|
110
|
+
pending_safety_checks=[],
|
|
111
|
+
status="completed",
|
|
112
|
+
type="computer_call"
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
def make_drag_item(path: List[Dict[str, int]], call_id: Optional[str] = None) -> ResponseComputerToolCallParam:
|
|
116
|
+
drag_path = [ActionDragPath(x=point["x"], y=point["y"]) for point in path]
|
|
117
|
+
return ResponseComputerToolCallParam(
|
|
118
|
+
id=random_id(),
|
|
119
|
+
call_id=call_id if call_id else random_id(),
|
|
120
|
+
action=ActionDrag(
|
|
121
|
+
path=drag_path,
|
|
122
|
+
type="drag"
|
|
123
|
+
),
|
|
124
|
+
pending_safety_checks=[],
|
|
125
|
+
status="completed",
|
|
126
|
+
type="computer_call"
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
def make_keypress_item(keys: List[str], call_id: Optional[str] = None) -> ResponseComputerToolCallParam:
|
|
130
|
+
return ResponseComputerToolCallParam(
|
|
131
|
+
id=random_id(),
|
|
132
|
+
call_id=call_id if call_id else random_id(),
|
|
133
|
+
action=ActionKeypress(
|
|
134
|
+
keys=keys,
|
|
135
|
+
type="keypress"
|
|
136
|
+
),
|
|
137
|
+
pending_safety_checks=[],
|
|
138
|
+
status="completed",
|
|
139
|
+
type="computer_call"
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
def make_move_item(x: int, y: int, call_id: Optional[str] = None) -> ResponseComputerToolCallParam:
|
|
143
|
+
return ResponseComputerToolCallParam(
|
|
144
|
+
id=random_id(),
|
|
145
|
+
call_id=call_id if call_id else random_id(),
|
|
146
|
+
action=ActionMove(
|
|
147
|
+
type="move",
|
|
148
|
+
x=x,
|
|
149
|
+
y=y
|
|
150
|
+
),
|
|
151
|
+
pending_safety_checks=[],
|
|
152
|
+
status="completed",
|
|
153
|
+
type="computer_call"
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
def make_screenshot_item(call_id: Optional[str] = None) -> ResponseComputerToolCallParam:
|
|
157
|
+
return ResponseComputerToolCallParam(
|
|
158
|
+
id=random_id(),
|
|
159
|
+
call_id=call_id if call_id else random_id(),
|
|
160
|
+
action=ActionScreenshot(
|
|
161
|
+
type="screenshot"
|
|
162
|
+
),
|
|
163
|
+
pending_safety_checks=[],
|
|
164
|
+
status="completed",
|
|
165
|
+
type="computer_call"
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
def make_scroll_item(x: int, y: int, scroll_x: int, scroll_y: int, call_id: Optional[str] = None) -> ResponseComputerToolCallParam:
|
|
169
|
+
return ResponseComputerToolCallParam(
|
|
170
|
+
id=random_id(),
|
|
171
|
+
call_id=call_id if call_id else random_id(),
|
|
172
|
+
action=ActionScroll(
|
|
173
|
+
scroll_x=scroll_x,
|
|
174
|
+
scroll_y=scroll_y,
|
|
175
|
+
type="scroll",
|
|
176
|
+
x=x,
|
|
177
|
+
y=y
|
|
178
|
+
),
|
|
179
|
+
pending_safety_checks=[],
|
|
180
|
+
status="completed",
|
|
181
|
+
type="computer_call"
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
def make_type_item(text: str, call_id: Optional[str] = None) -> ResponseComputerToolCallParam:
|
|
185
|
+
return ResponseComputerToolCallParam(
|
|
186
|
+
id=random_id(),
|
|
187
|
+
call_id=call_id if call_id else random_id(),
|
|
188
|
+
action=ActionTypeAction(
|
|
189
|
+
text=text,
|
|
190
|
+
type="type"
|
|
191
|
+
),
|
|
192
|
+
pending_safety_checks=[],
|
|
193
|
+
status="completed",
|
|
194
|
+
type="computer_call"
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
def make_wait_item(call_id: Optional[str] = None) -> ResponseComputerToolCallParam:
|
|
198
|
+
return ResponseComputerToolCallParam(
|
|
199
|
+
id=random_id(),
|
|
200
|
+
call_id=call_id if call_id else random_id(),
|
|
201
|
+
action=ActionWait(
|
|
202
|
+
type="wait"
|
|
203
|
+
),
|
|
204
|
+
pending_safety_checks=[],
|
|
205
|
+
status="completed",
|
|
206
|
+
type="computer_call"
|
|
207
|
+
)
|
agent/telemetry.py
CHANGED
|
@@ -1,21 +1,142 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""Agent telemetry for tracking anonymous usage and feature usage."""
|
|
2
2
|
|
|
3
|
+
import logging
|
|
3
4
|
import os
|
|
4
5
|
import platform
|
|
5
6
|
import sys
|
|
6
|
-
import
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
7
|
+
from typing import Dict, Any, Callable
|
|
8
|
+
|
|
9
|
+
# Import the core telemetry module
|
|
10
|
+
TELEMETRY_AVAILABLE = False
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
# Local fallbacks in case core telemetry isn't available
|
|
14
|
+
def _noop(*args: Any, **kwargs: Any) -> None:
|
|
15
|
+
"""No-op function for when telemetry is not available."""
|
|
16
|
+
pass
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
# Define default functions with unique names to avoid shadowing
|
|
20
|
+
_default_record_event = _noop
|
|
21
|
+
_default_increment_counter = _noop
|
|
22
|
+
_default_set_dimension = _noop
|
|
23
|
+
_default_get_telemetry_client = lambda: None
|
|
24
|
+
_default_flush = _noop
|
|
25
|
+
_default_is_telemetry_enabled = lambda: False
|
|
26
|
+
_default_is_telemetry_globally_disabled = lambda: True
|
|
27
|
+
|
|
28
|
+
# Set the actual functions to the defaults initially
|
|
29
|
+
record_event = _default_record_event
|
|
30
|
+
increment_counter = _default_increment_counter
|
|
31
|
+
set_dimension = _default_set_dimension
|
|
32
|
+
get_telemetry_client = _default_get_telemetry_client
|
|
33
|
+
flush = _default_flush
|
|
34
|
+
is_telemetry_enabled = _default_is_telemetry_enabled
|
|
35
|
+
is_telemetry_globally_disabled = _default_is_telemetry_globally_disabled
|
|
36
|
+
|
|
37
|
+
logger = logging.getLogger("agent.telemetry")
|
|
38
|
+
|
|
39
|
+
try:
|
|
40
|
+
# Import from core telemetry
|
|
41
|
+
from core.telemetry import (
|
|
42
|
+
record_event as core_record_event,
|
|
43
|
+
increment as core_increment,
|
|
44
|
+
get_telemetry_client as core_get_telemetry_client,
|
|
45
|
+
flush as core_flush,
|
|
46
|
+
is_telemetry_enabled as core_is_telemetry_enabled,
|
|
47
|
+
is_telemetry_globally_disabled as core_is_telemetry_globally_disabled,
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
# Override the default functions with actual implementations
|
|
51
|
+
record_event = core_record_event
|
|
52
|
+
get_telemetry_client = core_get_telemetry_client
|
|
53
|
+
flush = core_flush
|
|
54
|
+
is_telemetry_enabled = core_is_telemetry_enabled
|
|
55
|
+
is_telemetry_globally_disabled = core_is_telemetry_globally_disabled
|
|
56
|
+
|
|
57
|
+
def increment_counter(counter_name: str, value: int = 1) -> None:
|
|
58
|
+
"""Wrapper for increment to maintain backward compatibility."""
|
|
59
|
+
if is_telemetry_enabled():
|
|
60
|
+
core_increment(counter_name, value)
|
|
61
|
+
|
|
62
|
+
def set_dimension(name: str, value: Any) -> None:
|
|
63
|
+
"""Set a dimension that will be attached to all events."""
|
|
64
|
+
logger.debug(f"Setting dimension {name}={value}")
|
|
65
|
+
|
|
66
|
+
TELEMETRY_AVAILABLE = True
|
|
67
|
+
logger.info("Successfully imported telemetry")
|
|
68
|
+
except ImportError as e:
|
|
69
|
+
logger.warning(f"Could not import telemetry: {e}")
|
|
70
|
+
logger.debug("Telemetry not available, using no-op functions")
|
|
71
|
+
|
|
72
|
+
# Get system info once to use in telemetry
|
|
18
73
|
SYSTEM_INFO = {
|
|
19
|
-
"os":
|
|
74
|
+
"os": platform.system().lower(),
|
|
75
|
+
"os_version": platform.release(),
|
|
20
76
|
"python_version": platform.python_version(),
|
|
21
77
|
}
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def enable_telemetry() -> bool:
|
|
81
|
+
"""Enable telemetry if available.
|
|
82
|
+
|
|
83
|
+
Returns:
|
|
84
|
+
bool: True if telemetry was successfully enabled, False otherwise
|
|
85
|
+
"""
|
|
86
|
+
global TELEMETRY_AVAILABLE, record_event, increment_counter, get_telemetry_client, flush, is_telemetry_enabled, is_telemetry_globally_disabled
|
|
87
|
+
|
|
88
|
+
# Check if globally disabled using core function
|
|
89
|
+
if TELEMETRY_AVAILABLE and is_telemetry_globally_disabled():
|
|
90
|
+
logger.info("Telemetry is globally disabled via environment variable - cannot enable")
|
|
91
|
+
return False
|
|
92
|
+
|
|
93
|
+
# Already enabled
|
|
94
|
+
if TELEMETRY_AVAILABLE:
|
|
95
|
+
return True
|
|
96
|
+
|
|
97
|
+
# Try to import and enable
|
|
98
|
+
try:
|
|
99
|
+
from core.telemetry import (
|
|
100
|
+
record_event,
|
|
101
|
+
increment,
|
|
102
|
+
get_telemetry_client,
|
|
103
|
+
flush,
|
|
104
|
+
is_telemetry_globally_disabled,
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
# Check again after import
|
|
108
|
+
if is_telemetry_globally_disabled():
|
|
109
|
+
logger.info("Telemetry is globally disabled via environment variable - cannot enable")
|
|
110
|
+
return False
|
|
111
|
+
|
|
112
|
+
TELEMETRY_AVAILABLE = True
|
|
113
|
+
logger.info("Telemetry successfully enabled")
|
|
114
|
+
return True
|
|
115
|
+
except ImportError as e:
|
|
116
|
+
logger.warning(f"Could not enable telemetry: {e}")
|
|
117
|
+
return False
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def is_telemetry_enabled() -> bool:
|
|
121
|
+
"""Check if telemetry is enabled.
|
|
122
|
+
|
|
123
|
+
Returns:
|
|
124
|
+
bool: True if telemetry is enabled, False otherwise
|
|
125
|
+
"""
|
|
126
|
+
# Use the core function if available, otherwise use our local flag
|
|
127
|
+
if TELEMETRY_AVAILABLE:
|
|
128
|
+
from core.telemetry import is_telemetry_enabled as core_is_enabled
|
|
129
|
+
|
|
130
|
+
return core_is_enabled()
|
|
131
|
+
return False
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def record_agent_initialization() -> None:
|
|
135
|
+
"""Record when an agent instance is initialized."""
|
|
136
|
+
if TELEMETRY_AVAILABLE and is_telemetry_enabled():
|
|
137
|
+
record_event("agent_initialized", SYSTEM_INFO)
|
|
138
|
+
|
|
139
|
+
# Set dimensions that will be attached to all events
|
|
140
|
+
set_dimension("os", SYSTEM_INFO["os"])
|
|
141
|
+
set_dimension("os_version", SYSTEM_INFO["os_version"])
|
|
142
|
+
set_dimension("python_version", SYSTEM_INFO["python_version"])
|
agent/types.py
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Type definitions for agent
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from typing import Dict, List, Any, Optional, Callable, Protocol, Literal
|
|
6
|
+
from pydantic import BaseModel
|
|
7
|
+
import re
|
|
8
|
+
from litellm import ResponseInputParam, ResponsesAPIResponse, ToolParam
|
|
9
|
+
from collections.abc import Iterable
|
|
10
|
+
|
|
11
|
+
# Agent input types
|
|
12
|
+
Messages = str | ResponseInputParam
|
|
13
|
+
Tools = Optional[Iterable[ToolParam]]
|
|
14
|
+
|
|
15
|
+
# Agent output types
|
|
16
|
+
AgentResponse = ResponsesAPIResponse
|
|
17
|
+
|
|
18
|
+
# Agent loop registration
|
|
19
|
+
class AgentLoopInfo(BaseModel):
|
|
20
|
+
"""Information about a registered agent loop"""
|
|
21
|
+
func: Callable
|
|
22
|
+
models_regex: str
|
|
23
|
+
priority: int = 0
|
|
24
|
+
|
|
25
|
+
def matches_model(self, model: str) -> bool:
|
|
26
|
+
"""Check if this loop matches the given model"""
|
|
27
|
+
return bool(re.match(self.models_regex, model))
|
|
28
|
+
|
|
29
|
+
# Computer tool interface
|
|
30
|
+
class Computer(Protocol):
|
|
31
|
+
"""Protocol defining the interface for computer interactions."""
|
|
32
|
+
|
|
33
|
+
async def get_environment(self) -> Literal["windows", "mac", "linux", "browser"]:
|
|
34
|
+
"""Get the current environment type."""
|
|
35
|
+
...
|
|
36
|
+
|
|
37
|
+
async def get_dimensions(self) -> tuple[int, int]:
|
|
38
|
+
"""Get screen dimensions as (width, height)."""
|
|
39
|
+
...
|
|
40
|
+
|
|
41
|
+
async def screenshot(self) -> str:
|
|
42
|
+
"""Take a screenshot and return as base64 string."""
|
|
43
|
+
...
|
|
44
|
+
|
|
45
|
+
async def click(self, x: int, y: int, button: str = "left") -> None:
|
|
46
|
+
"""Click at coordinates with specified button."""
|
|
47
|
+
...
|
|
48
|
+
|
|
49
|
+
async def double_click(self, x: int, y: int) -> None:
|
|
50
|
+
"""Double click at coordinates."""
|
|
51
|
+
...
|
|
52
|
+
|
|
53
|
+
async def scroll(self, x: int, y: int, scroll_x: int, scroll_y: int) -> None:
|
|
54
|
+
"""Scroll at coordinates with specified scroll amounts."""
|
|
55
|
+
...
|
|
56
|
+
|
|
57
|
+
async def type(self, text: str) -> None:
|
|
58
|
+
"""Type text."""
|
|
59
|
+
...
|
|
60
|
+
|
|
61
|
+
async def wait(self, ms: int = 1000) -> None:
|
|
62
|
+
"""Wait for specified milliseconds."""
|
|
63
|
+
...
|
|
64
|
+
|
|
65
|
+
async def move(self, x: int, y: int) -> None:
|
|
66
|
+
"""Move cursor to coordinates."""
|
|
67
|
+
...
|
|
68
|
+
|
|
69
|
+
async def keypress(self, keys: List[str]) -> None:
|
|
70
|
+
"""Press key combination."""
|
|
71
|
+
...
|
|
72
|
+
|
|
73
|
+
async def drag(self, path: List[Dict[str, int]]) -> None:
|
|
74
|
+
"""Drag along specified path."""
|
|
75
|
+
...
|
|
76
|
+
|
|
77
|
+
async def get_current_url(self) -> str:
|
|
78
|
+
"""Get current URL (for browser environments)."""
|
|
79
|
+
...
|
agent/ui/__init__.py
CHANGED
agent/ui/__main__.py
CHANGED
|
@@ -1,15 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
Main entry point for agent.ui module.
|
|
3
|
-
|
|
4
|
-
This allows running the agent UI with:
|
|
5
|
-
python -m agent.ui
|
|
6
|
-
|
|
7
|
-
Instead of:
|
|
8
|
-
python -m agent.ui.gradio.app
|
|
9
|
-
"""
|
|
10
|
-
|
|
11
|
-
from .gradio.app import create_gradio_ui
|
|
1
|
+
from .gradio import launch_ui
|
|
12
2
|
|
|
13
3
|
if __name__ == "__main__":
|
|
14
|
-
|
|
15
|
-
app.launch(share=False, inbrowser=True)
|
|
4
|
+
launch_ui()
|
agent/ui/gradio/__init__.py
CHANGED
|
@@ -1,21 +1,8 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""
|
|
2
|
+
Gradio UI for agent
|
|
3
|
+
"""
|
|
2
4
|
|
|
3
|
-
|
|
4
|
-
from
|
|
5
|
+
from .app import launch_ui
|
|
6
|
+
from .ui_components import create_gradio_ui
|
|
5
7
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
def registry(name: str = "cua:gpt-4o") -> gr.Blocks:
|
|
10
|
-
"""Create and register a Gradio UI for the Computer-Use Agent.
|
|
11
|
-
|
|
12
|
-
Args:
|
|
13
|
-
name: The name to use for the Gradio app, in format 'provider:model'
|
|
14
|
-
|
|
15
|
-
Returns:
|
|
16
|
-
A Gradio Blocks application
|
|
17
|
-
"""
|
|
18
|
-
provider, model = name.split(":", 1) if ":" in name else ("openai", name)
|
|
19
|
-
|
|
20
|
-
# Create and return the Gradio UI
|
|
21
|
-
return create_gradio_ui(provider_name=provider, model_name=model)
|
|
8
|
+
__all__ = ["launch_ui", "create_gradio_ui"]
|