cua-agent 0.4.14__py3-none-any.whl → 0.4.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.
- agent/__init__.py +0 -9
- agent/agent.py +112 -88
- agent/callbacks/telemetry.py +8 -9
- agent/responses.py +47 -0
- agent/types.py +9 -0
- agent/ui/gradio/app.py +2 -2
- agent/ui/gradio/ui_components.py +2 -2
- {cua_agent-0.4.14.dist-info → cua_agent-0.4.16.dist-info}/METADATA +4 -4
- {cua_agent-0.4.14.dist-info → cua_agent-0.4.16.dist-info}/RECORD +11 -12
- agent/telemetry.py +0 -142
- {cua_agent-0.4.14.dist-info → cua_agent-0.4.16.dist-info}/WHEEL +0 -0
- {cua_agent-0.4.14.dist-info → cua_agent-0.4.16.dist-info}/entry_points.txt +0 -0
agent/__init__.py
CHANGED
|
@@ -28,13 +28,9 @@ try:
|
|
|
28
28
|
# Import from core telemetry for basic functions
|
|
29
29
|
from core.telemetry import (
|
|
30
30
|
is_telemetry_enabled,
|
|
31
|
-
flush,
|
|
32
31
|
record_event,
|
|
33
32
|
)
|
|
34
33
|
|
|
35
|
-
# Import set_dimension from our own telemetry module
|
|
36
|
-
from .telemetry import set_dimension
|
|
37
|
-
|
|
38
34
|
# Check if telemetry is enabled
|
|
39
35
|
if is_telemetry_enabled():
|
|
40
36
|
logger.info("Telemetry is enabled")
|
|
@@ -49,11 +45,6 @@ try:
|
|
|
49
45
|
},
|
|
50
46
|
)
|
|
51
47
|
|
|
52
|
-
# Set the package version as a dimension
|
|
53
|
-
set_dimension("agent_version", __version__)
|
|
54
|
-
|
|
55
|
-
# Flush events to ensure they're sent
|
|
56
|
-
flush()
|
|
57
48
|
else:
|
|
58
49
|
logger.info("Telemetry is disabled")
|
|
59
50
|
except ImportError as e:
|
agent/agent.py
CHANGED
|
@@ -7,7 +7,13 @@ from typing import Dict, List, Any, Optional, AsyncGenerator, Union, cast, Calla
|
|
|
7
7
|
|
|
8
8
|
from litellm.responses.utils import Usage
|
|
9
9
|
|
|
10
|
-
from .types import
|
|
10
|
+
from .types import (
|
|
11
|
+
Messages,
|
|
12
|
+
AgentCapability,
|
|
13
|
+
ToolError,
|
|
14
|
+
IllegalArgumentError
|
|
15
|
+
)
|
|
16
|
+
from .responses import make_tool_error_item, replace_failed_computer_calls_with_function_calls
|
|
11
17
|
from .decorators import find_agent_config
|
|
12
18
|
import json
|
|
13
19
|
import litellm
|
|
@@ -30,6 +36,15 @@ from .computers import (
|
|
|
30
36
|
make_computer_handler
|
|
31
37
|
)
|
|
32
38
|
|
|
39
|
+
def assert_callable_with(f, *args, **kwargs):
|
|
40
|
+
"""Check if function can be called with given arguments."""
|
|
41
|
+
try:
|
|
42
|
+
inspect.signature(f).bind(*args, **kwargs)
|
|
43
|
+
return True
|
|
44
|
+
except TypeError as e:
|
|
45
|
+
sig = inspect.signature(f)
|
|
46
|
+
raise IllegalArgumentError(f"Expected {sig}, got args={args} kwargs={kwargs}") from e
|
|
47
|
+
|
|
33
48
|
def get_json(obj: Any, max_depth: int = 10) -> Any:
|
|
34
49
|
def custom_serializer(o: Any, depth: int = 0, seen: Optional[Set[int]] = None) -> Any:
|
|
35
50
|
if seen is None:
|
|
@@ -405,7 +420,8 @@ class ComputerAgent:
|
|
|
405
420
|
|
|
406
421
|
async def _handle_item(self, item: Any, computer: Optional[AsyncComputerHandler] = None, ignore_call_ids: Optional[List[str]] = None) -> List[Dict[str, Any]]:
|
|
407
422
|
"""Handle each item; may cause a computer action + screenshot."""
|
|
408
|
-
|
|
423
|
+
call_id = item.get("call_id")
|
|
424
|
+
if ignore_call_ids and call_id and call_id in ignore_call_ids:
|
|
409
425
|
return []
|
|
410
426
|
|
|
411
427
|
item_type = item.get("type", None)
|
|
@@ -419,96 +435,103 @@ class ComputerAgent:
|
|
|
419
435
|
# print(content_item.get("text"))
|
|
420
436
|
return []
|
|
421
437
|
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
438
|
+
try:
|
|
439
|
+
if item_type == "computer_call":
|
|
440
|
+
await self._on_computer_call_start(item)
|
|
441
|
+
if not computer:
|
|
442
|
+
raise ValueError("Computer handler is required for computer calls")
|
|
443
|
+
|
|
444
|
+
# Perform computer actions
|
|
445
|
+
action = item.get("action")
|
|
446
|
+
action_type = action.get("type")
|
|
447
|
+
if action_type is None:
|
|
448
|
+
print(f"Action type cannot be `None`: action={action}, action_type={action_type}")
|
|
449
|
+
return []
|
|
450
|
+
|
|
451
|
+
# Extract action arguments (all fields except 'type')
|
|
452
|
+
action_args = {k: v for k, v in action.items() if k != "type"}
|
|
453
|
+
|
|
454
|
+
# print(f"{action_type}({action_args})")
|
|
455
|
+
|
|
456
|
+
# Execute the computer action
|
|
457
|
+
computer_method = getattr(computer, action_type, None)
|
|
458
|
+
if computer_method:
|
|
459
|
+
assert_callable_with(computer_method, **action_args)
|
|
460
|
+
await computer_method(**action_args)
|
|
461
|
+
else:
|
|
462
|
+
print(f"Unknown computer action: {action_type}")
|
|
463
|
+
return []
|
|
464
|
+
|
|
465
|
+
# Take screenshot after action
|
|
466
|
+
if self.screenshot_delay and self.screenshot_delay > 0:
|
|
467
|
+
await asyncio.sleep(self.screenshot_delay)
|
|
468
|
+
screenshot_base64 = await computer.screenshot()
|
|
469
|
+
await self._on_screenshot(screenshot_base64, "screenshot_after")
|
|
470
|
+
|
|
471
|
+
# Handle safety checks
|
|
472
|
+
pending_checks = item.get("pending_safety_checks", [])
|
|
473
|
+
acknowledged_checks = []
|
|
474
|
+
for check in pending_checks:
|
|
475
|
+
check_message = check.get("message", str(check))
|
|
476
|
+
acknowledged_checks.append(check)
|
|
477
|
+
# TODO: implement a callback for safety checks
|
|
478
|
+
# if acknowledge_safety_check_callback(check_message, allow_always=True):
|
|
479
|
+
# acknowledged_checks.append(check)
|
|
480
|
+
# else:
|
|
481
|
+
# raise ValueError(f"Safety check failed: {check_message}")
|
|
482
|
+
|
|
483
|
+
# Create call output
|
|
484
|
+
call_output = {
|
|
485
|
+
"type": "computer_call_output",
|
|
486
|
+
"call_id": item.get("call_id"),
|
|
487
|
+
"acknowledged_safety_checks": acknowledged_checks,
|
|
488
|
+
"output": {
|
|
489
|
+
"type": "input_image",
|
|
490
|
+
"image_url": f"data:image/png;base64,{screenshot_base64}",
|
|
491
|
+
},
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
# # Additional URL safety checks for browser environments
|
|
495
|
+
# if await computer.get_environment() == "browser":
|
|
496
|
+
# current_url = await computer.get_current_url()
|
|
497
|
+
# call_output["output"]["current_url"] = current_url
|
|
498
|
+
# # TODO: implement a callback for URL safety checks
|
|
499
|
+
# # check_blocklisted_url(current_url)
|
|
500
|
+
|
|
501
|
+
result = [call_output]
|
|
502
|
+
await self._on_computer_call_end(item, result)
|
|
503
|
+
return result
|
|
452
504
|
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
# TODO: implement a callback for safety checks
|
|
460
|
-
# if acknowledge_safety_check_callback(check_message, allow_always=True):
|
|
461
|
-
# acknowledged_checks.append(check)
|
|
462
|
-
# else:
|
|
463
|
-
# raise ValueError(f"Safety check failed: {check_message}")
|
|
505
|
+
if item_type == "function_call":
|
|
506
|
+
await self._on_function_call_start(item)
|
|
507
|
+
# Perform function call
|
|
508
|
+
function = self._get_tool(item.get("name"))
|
|
509
|
+
if not function:
|
|
510
|
+
raise ValueError(f"Function {item.get("name")} not found")
|
|
464
511
|
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
512
|
+
args = json.loads(item.get("arguments"))
|
|
513
|
+
|
|
514
|
+
# Validate arguments before execution
|
|
515
|
+
assert_callable_with(function, **args)
|
|
516
|
+
|
|
517
|
+
# Execute function - use asyncio.to_thread for non-async functions
|
|
518
|
+
if inspect.iscoroutinefunction(function):
|
|
519
|
+
result = await function(**args)
|
|
520
|
+
else:
|
|
521
|
+
result = await asyncio.to_thread(function, **args)
|
|
475
522
|
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
523
|
+
# Create function call output
|
|
524
|
+
call_output = {
|
|
525
|
+
"type": "function_call_output",
|
|
526
|
+
"call_id": item.get("call_id"),
|
|
527
|
+
"output": str(result),
|
|
528
|
+
}
|
|
482
529
|
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
await self._on_function_call_start(item)
|
|
489
|
-
# Perform function call
|
|
490
|
-
function = self._get_tool(item.get("name"))
|
|
491
|
-
if not function:
|
|
492
|
-
raise ValueError(f"Function {item.get("name")} not found")
|
|
493
|
-
|
|
494
|
-
args = json.loads(item.get("arguments"))
|
|
495
|
-
|
|
496
|
-
# Execute function - use asyncio.to_thread for non-async functions
|
|
497
|
-
if inspect.iscoroutinefunction(function):
|
|
498
|
-
result = await function(**args)
|
|
499
|
-
else:
|
|
500
|
-
result = await asyncio.to_thread(function, **args)
|
|
501
|
-
|
|
502
|
-
# Create function call output
|
|
503
|
-
call_output = {
|
|
504
|
-
"type": "function_call_output",
|
|
505
|
-
"call_id": item.get("call_id"),
|
|
506
|
-
"output": str(result),
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
result = [call_output]
|
|
510
|
-
await self._on_function_call_end(item, result)
|
|
511
|
-
return result
|
|
530
|
+
result = [call_output]
|
|
531
|
+
await self._on_function_call_end(item, result)
|
|
532
|
+
return result
|
|
533
|
+
except ToolError as e:
|
|
534
|
+
return [make_tool_error_item(repr(e), call_id)]
|
|
512
535
|
|
|
513
536
|
return []
|
|
514
537
|
|
|
@@ -569,6 +592,7 @@ class ComputerAgent:
|
|
|
569
592
|
# - PII anonymization
|
|
570
593
|
# - Image retention policy
|
|
571
594
|
combined_messages = old_items + new_items
|
|
595
|
+
combined_messages = replace_failed_computer_calls_with_function_calls(combined_messages)
|
|
572
596
|
preprocessed_messages = await self._on_llm_start(combined_messages)
|
|
573
597
|
|
|
574
598
|
loop_kwargs = {
|
agent/callbacks/telemetry.py
CHANGED
|
@@ -7,13 +7,18 @@ import uuid
|
|
|
7
7
|
from typing import List, Dict, Any, Optional, Union
|
|
8
8
|
|
|
9
9
|
from .base import AsyncCallbackHandler
|
|
10
|
-
from
|
|
10
|
+
from core.telemetry import (
|
|
11
11
|
record_event,
|
|
12
12
|
is_telemetry_enabled,
|
|
13
|
-
set_dimension,
|
|
14
|
-
SYSTEM_INFO,
|
|
15
13
|
)
|
|
16
14
|
|
|
15
|
+
import platform
|
|
16
|
+
|
|
17
|
+
SYSTEM_INFO = {
|
|
18
|
+
"os": platform.system().lower(),
|
|
19
|
+
"os_version": platform.release(),
|
|
20
|
+
"python_version": platform.python_version(),
|
|
21
|
+
}
|
|
17
22
|
|
|
18
23
|
class TelemetryCallback(AsyncCallbackHandler):
|
|
19
24
|
"""
|
|
@@ -65,11 +70,6 @@ class TelemetryCallback(AsyncCallbackHandler):
|
|
|
65
70
|
**SYSTEM_INFO
|
|
66
71
|
}
|
|
67
72
|
|
|
68
|
-
# Set session-level dimensions
|
|
69
|
-
set_dimension("session_id", self.session_id)
|
|
70
|
-
set_dimension("agent_type", agent_info["agent_type"])
|
|
71
|
-
set_dimension("model", agent_info["model"])
|
|
72
|
-
|
|
73
73
|
record_event("agent_session_start", agent_info)
|
|
74
74
|
|
|
75
75
|
async def on_run_start(self, kwargs: Dict[str, Any], old_items: List[Dict[str, Any]]) -> None:
|
|
@@ -98,7 +98,6 @@ class TelemetryCallback(AsyncCallbackHandler):
|
|
|
98
98
|
if trajectory:
|
|
99
99
|
run_data["uploaded_trajectory"] = trajectory
|
|
100
100
|
|
|
101
|
-
set_dimension("run_id", self.run_id)
|
|
102
101
|
record_event("agent_run_start", run_data)
|
|
103
102
|
|
|
104
103
|
async def on_run_end(self, kwargs: Dict[str, Any], old_items: List[Dict[str, Any]], new_items: List[Dict[str, Any]]) -> None:
|
agent/responses.py
CHANGED
|
@@ -252,6 +252,53 @@ def make_failed_tool_call_items(tool_name: str, tool_kwargs: Dict[str, Any], err
|
|
|
252
252
|
}
|
|
253
253
|
]
|
|
254
254
|
|
|
255
|
+
def make_tool_error_item(error_message: str, call_id: Optional[str] = None) -> Dict[str, Any]:
|
|
256
|
+
call_id = call_id if call_id else random_id()
|
|
257
|
+
return {
|
|
258
|
+
"type": "function_call_output",
|
|
259
|
+
"call_id": call_id,
|
|
260
|
+
"output": json.dumps({"error": error_message}),
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
def replace_failed_computer_calls_with_function_calls(messages: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
|
|
264
|
+
"""
|
|
265
|
+
Replace computer_call items with function_call items if they share a call_id with a function_call_output.
|
|
266
|
+
This indicates the computer call failed and should be treated as a function call instead.
|
|
267
|
+
We do this because the computer_call_output items do not support text output.
|
|
268
|
+
|
|
269
|
+
Args:
|
|
270
|
+
messages: List of message items to process
|
|
271
|
+
"""
|
|
272
|
+
messages = messages.copy()
|
|
273
|
+
|
|
274
|
+
# Find all call_ids that have function_call_output items
|
|
275
|
+
failed_call_ids = set()
|
|
276
|
+
for msg in messages:
|
|
277
|
+
if msg.get("type") == "function_call_output":
|
|
278
|
+
call_id = msg.get("call_id")
|
|
279
|
+
if call_id:
|
|
280
|
+
failed_call_ids.add(call_id)
|
|
281
|
+
|
|
282
|
+
# Replace computer_call items that have matching call_ids
|
|
283
|
+
for i, msg in enumerate(messages):
|
|
284
|
+
if (msg.get("type") == "computer_call" and
|
|
285
|
+
msg.get("call_id") in failed_call_ids):
|
|
286
|
+
|
|
287
|
+
# Extract action from computer_call
|
|
288
|
+
action = msg.get("action", {})
|
|
289
|
+
call_id = msg.get("call_id")
|
|
290
|
+
|
|
291
|
+
# Create function_call replacement
|
|
292
|
+
messages[i] = {
|
|
293
|
+
"type": "function_call",
|
|
294
|
+
"id": msg.get("id", random_id()),
|
|
295
|
+
"call_id": call_id,
|
|
296
|
+
"name": "computer",
|
|
297
|
+
"arguments": json.dumps(action),
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
return messages
|
|
301
|
+
|
|
255
302
|
# Conversion functions between element descriptions and coordinates
|
|
256
303
|
def convert_computer_calls_desc2xy(responses_items: List[Dict[str, Any]], desc2xy: Dict[str, tuple]) -> List[Dict[str, Any]]:
|
|
257
304
|
"""
|
agent/types.py
CHANGED
|
@@ -16,6 +16,15 @@ Tools = Optional[Iterable[ToolParam]]
|
|
|
16
16
|
AgentResponse = ResponsesAPIResponse
|
|
17
17
|
AgentCapability = Literal["step", "click"]
|
|
18
18
|
|
|
19
|
+
# Exception types
|
|
20
|
+
class ToolError(RuntimeError):
|
|
21
|
+
"""Base exception for tool-related errors"""
|
|
22
|
+
pass
|
|
23
|
+
|
|
24
|
+
class IllegalArgumentError(ToolError):
|
|
25
|
+
"""Exception raised when function arguments are invalid"""
|
|
26
|
+
pass
|
|
27
|
+
|
|
19
28
|
|
|
20
29
|
# Agent config registration
|
|
21
30
|
class AgentConfigInfo(BaseModel):
|
agent/ui/gradio/app.py
CHANGED
|
@@ -114,14 +114,14 @@ MODEL_MAPPINGS = {
|
|
|
114
114
|
"Anthropic: Claude 4 Opus (20250514)": "anthropic/claude-opus-4-20250514",
|
|
115
115
|
"Anthropic: Claude 4 Sonnet (20250514)": "anthropic/claude-sonnet-4-20250514",
|
|
116
116
|
"Anthropic: Claude 3.7 Sonnet (20250219)": "anthropic/claude-3-7-sonnet-20250219",
|
|
117
|
-
"Anthropic: Claude 3.5 Sonnet (
|
|
117
|
+
"Anthropic: Claude 3.5 Sonnet (20241022)": "anthropic/claude-3-5-sonnet-20241022",
|
|
118
118
|
},
|
|
119
119
|
"omni": {
|
|
120
120
|
"default": "omniparser+openai/gpt-4o",
|
|
121
121
|
"OMNI: OpenAI GPT-4o": "omniparser+openai/gpt-4o",
|
|
122
122
|
"OMNI: OpenAI GPT-4o mini": "omniparser+openai/gpt-4o-mini",
|
|
123
123
|
"OMNI: Claude 3.7 Sonnet (20250219)": "omniparser+anthropic/claude-3-7-sonnet-20250219",
|
|
124
|
-
"OMNI: Claude 3.5 Sonnet (
|
|
124
|
+
"OMNI: Claude 3.5 Sonnet (20241022)": "omniparser+anthropic/claude-3-5-sonnet-20241022",
|
|
125
125
|
},
|
|
126
126
|
"uitars": {
|
|
127
127
|
"default": "huggingface-local/ByteDance-Seed/UI-TARS-1.5-7B" if is_mac else "ui-tars",
|
agent/ui/gradio/ui_components.py
CHANGED
|
@@ -38,13 +38,13 @@ def create_gradio_ui() -> gr.Blocks:
|
|
|
38
38
|
"Anthropic: Claude 4 Opus (20250514)",
|
|
39
39
|
"Anthropic: Claude 4 Sonnet (20250514)",
|
|
40
40
|
"Anthropic: Claude 3.7 Sonnet (20250219)",
|
|
41
|
-
"Anthropic: Claude 3.5 Sonnet (
|
|
41
|
+
"Anthropic: Claude 3.5 Sonnet (20241022)",
|
|
42
42
|
]
|
|
43
43
|
omni_models = [
|
|
44
44
|
"OMNI: OpenAI GPT-4o",
|
|
45
45
|
"OMNI: OpenAI GPT-4o mini",
|
|
46
46
|
"OMNI: Claude 3.7 Sonnet (20250219)",
|
|
47
|
-
"OMNI: Claude 3.5 Sonnet (
|
|
47
|
+
"OMNI: Claude 3.5 Sonnet (20241022)"
|
|
48
48
|
]
|
|
49
49
|
|
|
50
50
|
# Check if API keys are available
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: cua-agent
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.16
|
|
4
4
|
Summary: CUA (Computer Use) Agent for AI-driven computer interaction
|
|
5
5
|
Author-Email: TryCua <gh@trycua.com>
|
|
6
6
|
Requires-Python: >=3.12
|
|
@@ -56,8 +56,8 @@ Description-Content-Type: text/markdown
|
|
|
56
56
|
<h1>
|
|
57
57
|
<div class="image-wrapper" style="display: inline-block;">
|
|
58
58
|
<picture>
|
|
59
|
-
<source media="(prefers-color-scheme: dark)" alt="logo" height="150" srcset="
|
|
60
|
-
<source media="(prefers-color-scheme: light)" alt="logo" height="150" srcset="
|
|
59
|
+
<source media="(prefers-color-scheme: dark)" alt="logo" height="150" srcset="https://raw.githubusercontent.com/trycua/cua/main/img/logo_white.png" style="display: block; margin: auto;">
|
|
60
|
+
<source media="(prefers-color-scheme: light)" alt="logo" height="150" srcset="https://raw.githubusercontent.com/trycua/cua/main/img/logo_black.png" style="display: block; margin: auto;">
|
|
61
61
|
<img alt="Shows my svg">
|
|
62
62
|
</picture>
|
|
63
63
|
</div>
|
|
@@ -138,7 +138,7 @@ if __name__ == "__main__":
|
|
|
138
138
|
### Anthropic Claude (Computer Use API)
|
|
139
139
|
```python
|
|
140
140
|
model="anthropic/claude-3-5-sonnet-20241022"
|
|
141
|
-
model="anthropic/claude-3-
|
|
141
|
+
model="anthropic/claude-3-7-sonnet-20250219"
|
|
142
142
|
model="anthropic/claude-opus-4-20250514"
|
|
143
143
|
model="anthropic/claude-sonnet-4-20250514"
|
|
144
144
|
```
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
agent/__init__.py,sha256=
|
|
1
|
+
agent/__init__.py,sha256=MaW-BczJ-lCACPYH39DvFhE7ZWiSo7sBO6pBfyO7Nxc,1269
|
|
2
2
|
agent/__main__.py,sha256=lBUe8Niqa5XoCjwFfXyX7GtnUwjjZXC1-j4V9mvUYSc,538
|
|
3
3
|
agent/adapters/__init__.py,sha256=lNH6srgIMmZOI7dgicJs3LCk_1MeqLF0lou9n7b23Ts,238
|
|
4
4
|
agent/adapters/huggingfacelocal_adapter.py,sha256=Uqjtcohhzd33VFh38Ra2y4Uv_lTghMswoqS1t-KKFkw,8480
|
|
5
5
|
agent/adapters/human_adapter.py,sha256=xT4nnfNXb1z-vnGFlLmFEZN7TMcoMBGS40MtR1Zwv4o,13079
|
|
6
|
-
agent/agent.py,sha256=
|
|
6
|
+
agent/agent.py,sha256=Zo7K7FacdCwGUDW3cuMCpJ1h9tkULH3hrgx94tdjCsk,29123
|
|
7
7
|
agent/callbacks/__init__.py,sha256=yxxBXUqpXQ-jRi_ixJMtmQPxoNRy5Vz1PUBzNNa1Dwg,538
|
|
8
8
|
agent/callbacks/base.py,sha256=UnnnYlh6XCm6HKZZsAPaT_Eyo9LUYLyjyNwF-QRm6Ns,4691
|
|
9
9
|
agent/callbacks/budget_manager.py,sha256=RyKM-7iXQcDotYvrw3eURzeEHEXvQjID-NobtvQWE7k,1832
|
|
10
10
|
agent/callbacks/image_retention.py,sha256=tiuRT5ke9xXTb2eP8Gz-2ITyAMY29LURUH6AbjX3RP8,6165
|
|
11
11
|
agent/callbacks/logging.py,sha256=OOxU97EzrxlnUAtiEnvy9FB7SwCUK90-rdpDFA2Ae4E,10921
|
|
12
12
|
agent/callbacks/pii_anonymization.py,sha256=NEkUTUjQBi82nqus7kT-1E4RaeQ2hQrY7YCnKndLhP8,3272
|
|
13
|
-
agent/callbacks/telemetry.py,sha256=
|
|
13
|
+
agent/callbacks/telemetry.py,sha256=RbUDhE41mTi8g9hNre0EpltK_NUZkLj8buJLWBzs0Ek,7363
|
|
14
14
|
agent/callbacks/trajectory_saver.py,sha256=VHbiDQzI_XludkWhZIVqIMrsxgwKfFWwVtqaRot_D4U,12231
|
|
15
15
|
agent/cli.py,sha256=AgaXwywHd3nGQWuqMRj6SbPyFaCPjfo5980Y1ApQOTQ,12413
|
|
16
16
|
agent/computers/__init__.py,sha256=39ISJsaREaQIZckpzxSuLhuR763wUU3TxUux78EKjAg,1477
|
|
@@ -36,15 +36,14 @@ agent/loops/model_types.csv,sha256=GmFn4x80yoUpQZuQ-GXtJkPVlOLYWZ5u_5A73HRyeNE,1
|
|
|
36
36
|
agent/loops/omniparser.py,sha256=-db8JUL2Orn47ERIaLbuNShAXn4LeIgYzRWphn_9Dg4,15071
|
|
37
37
|
agent/loops/openai.py,sha256=8Ad_XufpENmLq1nEnhzF3oswPrPK1EPz-C5NU8UOEs0,8035
|
|
38
38
|
agent/loops/uitars.py,sha256=PVNOdwcn2K6RgaxoU-9I4HjBTsEH073M11LTqTrN7C4,31849
|
|
39
|
-
agent/responses.py,sha256=
|
|
40
|
-
agent/
|
|
41
|
-
agent/types.py,sha256=ZoWY8a3GZtB8V0SnOzoI7DQy4nP_GRubxJKbuLPOc8c,840
|
|
39
|
+
agent/responses.py,sha256=_SoN4BkaTxMHMB21EOtDc_aDBIJlfDwsCzszMBnIkH0,30764
|
|
40
|
+
agent/types.py,sha256=h6SnmTAEAaryVCjwVZFAuCbio9UW13OqgQEV7HKmZVM,1060
|
|
42
41
|
agent/ui/__init__.py,sha256=DTZpK85QXscXK2nM9HtpAhVBF13yAamUrtwrQSuV-kM,126
|
|
43
42
|
agent/ui/__main__.py,sha256=vudWXYvGM0aNT5aZ94HPtGW8YXOZ4cLXepHyhUM_k1g,73
|
|
44
43
|
agent/ui/gradio/__init__.py,sha256=yv4Mrfo-Sj2U5sVn_UJHAuwYCezo-5O4ItR2C9jzNko,145
|
|
45
|
-
agent/ui/gradio/app.py,sha256=
|
|
46
|
-
agent/ui/gradio/ui_components.py,sha256=
|
|
47
|
-
cua_agent-0.4.
|
|
48
|
-
cua_agent-0.4.
|
|
49
|
-
cua_agent-0.4.
|
|
50
|
-
cua_agent-0.4.
|
|
44
|
+
agent/ui/gradio/app.py,sha256=Ol97YEbwREZZQ9_PMjVHlfOcu9BGsawxgAGAm79hT80,9117
|
|
45
|
+
agent/ui/gradio/ui_components.py,sha256=dJUvKDmc1oSejtoR_gU_oWWYwxaOOQyPloSYRGMrUCQ,36068
|
|
46
|
+
cua_agent-0.4.16.dist-info/METADATA,sha256=iKOsC1Me0Rq_jQrhfgLN-uY1KR5OtKIQXpRGXpnH_LE,12698
|
|
47
|
+
cua_agent-0.4.16.dist-info/WHEEL,sha256=9P2ygRxDrTJz3gsagc0Z96ukrxjr-LFBGOgv3AuKlCA,90
|
|
48
|
+
cua_agent-0.4.16.dist-info/entry_points.txt,sha256=6OYgBcLyFCUgeqLgnvMyOJxPCWzgy7se4rLPKtNonMs,34
|
|
49
|
+
cua_agent-0.4.16.dist-info/RECORD,,
|
agent/telemetry.py
DELETED
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
"""Agent telemetry for tracking anonymous usage and feature usage."""
|
|
2
|
-
|
|
3
|
-
import logging
|
|
4
|
-
import os
|
|
5
|
-
import platform
|
|
6
|
-
import sys
|
|
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
|
|
73
|
-
SYSTEM_INFO = {
|
|
74
|
-
"os": platform.system().lower(),
|
|
75
|
-
"os_version": platform.release(),
|
|
76
|
-
"python_version": platform.python_version(),
|
|
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"])
|
|
File without changes
|
|
File without changes
|