cua-agent 0.4.14__py3-none-any.whl → 0.7.16__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.

Files changed (82) hide show
  1. agent/__init__.py +4 -19
  2. agent/__main__.py +2 -1
  3. agent/adapters/__init__.py +6 -0
  4. agent/adapters/azure_ml_adapter.py +283 -0
  5. agent/adapters/cua_adapter.py +161 -0
  6. agent/adapters/huggingfacelocal_adapter.py +67 -125
  7. agent/adapters/human_adapter.py +116 -114
  8. agent/adapters/mlxvlm_adapter.py +370 -0
  9. agent/adapters/models/__init__.py +41 -0
  10. agent/adapters/models/generic.py +78 -0
  11. agent/adapters/models/internvl.py +290 -0
  12. agent/adapters/models/opencua.py +115 -0
  13. agent/adapters/models/qwen2_5_vl.py +78 -0
  14. agent/agent.py +431 -241
  15. agent/callbacks/__init__.py +10 -3
  16. agent/callbacks/base.py +45 -31
  17. agent/callbacks/budget_manager.py +22 -10
  18. agent/callbacks/image_retention.py +54 -98
  19. agent/callbacks/logging.py +55 -42
  20. agent/callbacks/operator_validator.py +140 -0
  21. agent/callbacks/otel.py +291 -0
  22. agent/callbacks/pii_anonymization.py +19 -16
  23. agent/callbacks/prompt_instructions.py +47 -0
  24. agent/callbacks/telemetry.py +106 -69
  25. agent/callbacks/trajectory_saver.py +178 -70
  26. agent/cli.py +269 -119
  27. agent/computers/__init__.py +14 -9
  28. agent/computers/base.py +32 -19
  29. agent/computers/cua.py +52 -25
  30. agent/computers/custom.py +78 -71
  31. agent/decorators.py +23 -14
  32. agent/human_tool/__init__.py +2 -7
  33. agent/human_tool/__main__.py +6 -2
  34. agent/human_tool/server.py +48 -37
  35. agent/human_tool/ui.py +359 -235
  36. agent/integrations/hud/__init__.py +164 -74
  37. agent/integrations/hud/agent.py +338 -342
  38. agent/integrations/hud/proxy.py +297 -0
  39. agent/loops/__init__.py +44 -14
  40. agent/loops/anthropic.py +590 -492
  41. agent/loops/base.py +19 -15
  42. agent/loops/composed_grounded.py +142 -144
  43. agent/loops/fara/__init__.py +8 -0
  44. agent/loops/fara/config.py +506 -0
  45. agent/loops/fara/helpers.py +357 -0
  46. agent/loops/fara/schema.py +143 -0
  47. agent/loops/gelato.py +183 -0
  48. agent/loops/gemini.py +935 -0
  49. agent/loops/generic_vlm.py +601 -0
  50. agent/loops/glm45v.py +140 -135
  51. agent/loops/gta1.py +48 -51
  52. agent/loops/holo.py +218 -0
  53. agent/loops/internvl.py +180 -0
  54. agent/loops/moondream3.py +493 -0
  55. agent/loops/omniparser.py +326 -226
  56. agent/loops/openai.py +63 -56
  57. agent/loops/opencua.py +134 -0
  58. agent/loops/uiins.py +175 -0
  59. agent/loops/uitars.py +262 -212
  60. agent/loops/uitars2.py +951 -0
  61. agent/playground/__init__.py +5 -0
  62. agent/playground/server.py +301 -0
  63. agent/proxy/examples.py +196 -0
  64. agent/proxy/handlers.py +255 -0
  65. agent/responses.py +486 -339
  66. agent/tools/__init__.py +24 -0
  67. agent/tools/base.py +253 -0
  68. agent/tools/browser_tool.py +423 -0
  69. agent/types.py +20 -5
  70. agent/ui/__init__.py +1 -1
  71. agent/ui/__main__.py +1 -1
  72. agent/ui/gradio/app.py +25 -22
  73. agent/ui/gradio/ui_components.py +314 -167
  74. cua_agent-0.7.16.dist-info/METADATA +85 -0
  75. cua_agent-0.7.16.dist-info/RECORD +79 -0
  76. {cua_agent-0.4.14.dist-info → cua_agent-0.7.16.dist-info}/WHEEL +1 -1
  77. agent/integrations/hud/adapter.py +0 -121
  78. agent/integrations/hud/computer_handler.py +0 -187
  79. agent/telemetry.py +0 -142
  80. cua_agent-0.4.14.dist-info/METADATA +0 -436
  81. cua_agent-0.4.14.dist-info/RECORD +0 -50
  82. {cua_agent-0.4.14.dist-info → cua_agent-0.7.16.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,24 @@
1
+ """
2
+ Agent tools module.
3
+ Provides base classes and registered tools for agent interactions.
4
+ """
5
+
6
+ from .base import (
7
+ TOOL_REGISTRY,
8
+ BaseComputerTool,
9
+ BaseTool,
10
+ get_registered_tools,
11
+ get_tool,
12
+ register_tool,
13
+ )
14
+ from .browser_tool import BrowserTool
15
+
16
+ __all__ = [
17
+ "BaseTool",
18
+ "BaseComputerTool",
19
+ "register_tool",
20
+ "get_registered_tools",
21
+ "get_tool",
22
+ "TOOL_REGISTRY",
23
+ "BrowserTool",
24
+ ]
agent/tools/base.py ADDED
@@ -0,0 +1,253 @@
1
+ """
2
+ Base tool interface and registration system for agent tools.
3
+ Provides a protocol for implementing tools that can be registered and discovered.
4
+ """
5
+
6
+ import json
7
+ from abc import ABC, abstractmethod
8
+ from typing import Dict, List, Optional, Union
9
+
10
+ # Global tool registry
11
+ TOOL_REGISTRY: Dict[str, type] = {}
12
+
13
+
14
+ def register_tool(name: str, allow_overwrite: bool = False):
15
+ """
16
+ Decorator to register a tool class with a given name.
17
+
18
+ Args:
19
+ name: The name to register the tool under
20
+ allow_overwrite: Whether to allow overwriting an existing tool with the same name
21
+
22
+ Returns:
23
+ Decorator function that registers the class
24
+
25
+ Example:
26
+ @register_tool("my_tool")
27
+ class MyTool(BaseTool):
28
+ ...
29
+ """
30
+
31
+ def decorator(cls):
32
+ if name in TOOL_REGISTRY:
33
+ if allow_overwrite:
34
+ print(f"Warning: Tool `{name}` already exists! Overwriting with class {cls}.")
35
+ else:
36
+ raise ValueError(
37
+ f"Tool `{name}` already exists! Please ensure that the tool name is unique."
38
+ )
39
+ if hasattr(cls, "name") and cls.name and (cls.name != name):
40
+ raise ValueError(
41
+ f'{cls.__name__}.name="{cls.name}" conflicts with @register_tool(name="{name}").'
42
+ )
43
+ cls.name = name
44
+ TOOL_REGISTRY[name] = cls
45
+ return cls
46
+
47
+ return decorator
48
+
49
+
50
+ def is_tool_schema(obj: dict) -> bool:
51
+ """
52
+ Check if obj is a valid JSON schema describing a tool compatible with OpenAI's tool calling.
53
+
54
+ Example valid schema:
55
+ {
56
+ "name": "get_current_weather",
57
+ "description": "Get the current weather in a given location",
58
+ "parameters": {
59
+ "type": "object",
60
+ "properties": {
61
+ "location": {
62
+ "type": "string",
63
+ "description": "The city and state, e.g. San Francisco, CA"
64
+ },
65
+ "unit": {
66
+ "type": "string",
67
+ "enum": ["celsius", "fahrenheit"]
68
+ }
69
+ },
70
+ "required": ["location"]
71
+ }
72
+ }
73
+ """
74
+ try:
75
+ # Basic structure validation
76
+ assert set(obj.keys()) == {"name", "description", "parameters"}
77
+ assert isinstance(obj["name"], str)
78
+ assert obj["name"].strip()
79
+ assert isinstance(obj["description"], str)
80
+ assert isinstance(obj["parameters"], dict)
81
+
82
+ # Parameters structure validation
83
+ assert "type" in obj["parameters"]
84
+ assert obj["parameters"]["type"] == "object"
85
+ assert "properties" in obj["parameters"]
86
+ assert isinstance(obj["parameters"]["properties"], dict)
87
+
88
+ if "required" in obj["parameters"]:
89
+ assert isinstance(obj["parameters"]["required"], list)
90
+ assert set(obj["parameters"]["required"]).issubset(
91
+ set(obj["parameters"]["properties"].keys())
92
+ )
93
+
94
+ return True
95
+ except (AssertionError, KeyError, TypeError):
96
+ return False
97
+
98
+
99
+ class BaseTool(ABC):
100
+ """
101
+ Base class for all agent tools.
102
+
103
+ Tools must implement:
104
+ - name: str - The tool name (set by @register_tool decorator)
105
+ - description: property that returns str - Tool description
106
+ - parameters: property that returns dict - JSON schema for tool parameters
107
+ - call: method - Execute the tool with given parameters
108
+ """
109
+
110
+ name: str = ""
111
+
112
+ def __init__(self, cfg: Optional[dict] = None):
113
+ """
114
+ Initialize the tool.
115
+
116
+ Args:
117
+ cfg: Optional configuration dictionary
118
+ """
119
+ self.cfg = cfg or {}
120
+
121
+ if not self.name:
122
+ raise ValueError(
123
+ f"You must set {self.__class__.__name__}.name, either by "
124
+ f"@register_tool(name=...) or explicitly setting "
125
+ f"{self.__class__.__name__}.name"
126
+ )
127
+
128
+ # Validate schema if parameters is a dict
129
+ if isinstance(self.parameters, dict):
130
+ if not is_tool_schema(
131
+ {"name": self.name, "description": self.description, "parameters": self.parameters}
132
+ ):
133
+ raise ValueError(
134
+ "The parameters, when provided as a dict, must conform to a "
135
+ "valid openai-compatible JSON schema."
136
+ )
137
+
138
+ @property
139
+ @abstractmethod
140
+ def description(self) -> str:
141
+ """Return the tool description."""
142
+ raise NotImplementedError
143
+
144
+ @property
145
+ @abstractmethod
146
+ def parameters(self) -> dict:
147
+ """Return the JSON schema for tool parameters."""
148
+ raise NotImplementedError
149
+
150
+ @abstractmethod
151
+ def call(self, params: Union[str, dict], **kwargs) -> Union[str, list, dict]:
152
+ """
153
+ Execute the tool with the given parameters.
154
+
155
+ Args:
156
+ params: The parameters for the tool call (JSON string or dict)
157
+ **kwargs: Additional keyword arguments
158
+
159
+ Returns:
160
+ The result of the tool execution
161
+ """
162
+ raise NotImplementedError
163
+
164
+ def _verify_json_format_args(self, params: Union[str, dict]) -> dict:
165
+ """
166
+ Verify and parse the parameters as JSON.
167
+
168
+ Args:
169
+ params: Parameters as string or dict
170
+
171
+ Returns:
172
+ Parsed parameters as dict
173
+
174
+ Raises:
175
+ ValueError: If parameters are not valid JSON or don't match schema
176
+ """
177
+ if isinstance(params, str):
178
+ try:
179
+ params_json: dict = json.loads(params)
180
+ except json.JSONDecodeError as e:
181
+ raise ValueError(f"Parameters must be formatted as valid JSON: {e}")
182
+ else:
183
+ params_json: dict = params
184
+
185
+ # Validate against schema if using dict parameters
186
+ if isinstance(self.parameters, dict):
187
+ try:
188
+ # Basic validation of required fields
189
+ if "required" in self.parameters:
190
+ for field in self.parameters["required"]:
191
+ if field not in params_json:
192
+ raise ValueError(f'Required parameter "{field}" is missing')
193
+ except (KeyError, TypeError) as e:
194
+ raise ValueError(f"Invalid parameters: {e}")
195
+
196
+ return params_json
197
+
198
+ @property
199
+ def function(self) -> dict:
200
+ """
201
+ Return the function information for this tool.
202
+
203
+ Returns:
204
+ Dict with tool metadata
205
+ """
206
+ return {
207
+ "name": self.name,
208
+ "description": self.description,
209
+ "parameters": self.parameters,
210
+ }
211
+
212
+
213
+ def get_registered_tools() -> Dict[str, type]:
214
+ """
215
+ Get all registered tools.
216
+
217
+ Returns:
218
+ Dictionary mapping tool names to tool classes
219
+ """
220
+ return TOOL_REGISTRY.copy()
221
+
222
+
223
+ def get_tool(name: str) -> Optional[type]:
224
+ """
225
+ Get a registered tool by name.
226
+
227
+ Args:
228
+ name: The tool name
229
+
230
+ Returns:
231
+ The tool class, or None if not found
232
+ """
233
+ return TOOL_REGISTRY.get(name)
234
+
235
+
236
+ class BaseComputerTool(BaseTool):
237
+ """
238
+ Base class for computer tools that can provide screenshots.
239
+
240
+ Computer tools must implement:
241
+ - All BaseTool requirements (name, description, parameters, call)
242
+ - screenshot() method that returns screenshot as base64 string
243
+ """
244
+
245
+ @abstractmethod
246
+ async def screenshot(self) -> str:
247
+ """
248
+ Take a screenshot of the computer/browser.
249
+
250
+ Returns:
251
+ Screenshot image data as base64-encoded string
252
+ """
253
+ raise NotImplementedError