cua-agent 0.3.2__py3-none-any.whl → 0.4.0b2__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 (111) hide show
  1. agent/__init__.py +15 -51
  2. agent/__main__.py +21 -0
  3. agent/adapters/__init__.py +9 -0
  4. agent/adapters/huggingfacelocal_adapter.py +229 -0
  5. agent/agent.py +577 -0
  6. agent/callbacks/__init__.py +17 -0
  7. agent/callbacks/base.py +153 -0
  8. agent/callbacks/budget_manager.py +44 -0
  9. agent/callbacks/image_retention.py +139 -0
  10. agent/callbacks/logging.py +247 -0
  11. agent/callbacks/pii_anonymization.py +259 -0
  12. agent/callbacks/trajectory_saver.py +305 -0
  13. agent/cli.py +290 -0
  14. agent/computer_handler.py +107 -0
  15. agent/decorators.py +90 -0
  16. agent/loops/__init__.py +11 -0
  17. agent/loops/anthropic.py +728 -0
  18. agent/loops/omniparser.py +339 -0
  19. agent/loops/openai.py +95 -0
  20. agent/loops/uitars.py +688 -0
  21. agent/responses.py +207 -0
  22. agent/types.py +79 -0
  23. agent/ui/__init__.py +7 -1
  24. agent/ui/gradio/__init__.py +6 -19
  25. agent/ui/gradio/app.py +80 -1299
  26. agent/ui/gradio/ui_components.py +703 -0
  27. cua_agent-0.4.0b2.dist-info/METADATA +424 -0
  28. cua_agent-0.4.0b2.dist-info/RECORD +30 -0
  29. agent/core/__init__.py +0 -27
  30. agent/core/agent.py +0 -210
  31. agent/core/base.py +0 -217
  32. agent/core/callbacks.py +0 -200
  33. agent/core/experiment.py +0 -249
  34. agent/core/factory.py +0 -122
  35. agent/core/messages.py +0 -332
  36. agent/core/provider_config.py +0 -21
  37. agent/core/telemetry.py +0 -142
  38. agent/core/tools/__init__.py +0 -21
  39. agent/core/tools/base.py +0 -74
  40. agent/core/tools/bash.py +0 -52
  41. agent/core/tools/collection.py +0 -46
  42. agent/core/tools/computer.py +0 -113
  43. agent/core/tools/edit.py +0 -67
  44. agent/core/tools/manager.py +0 -56
  45. agent/core/tools.py +0 -32
  46. agent/core/types.py +0 -88
  47. agent/core/visualization.py +0 -197
  48. agent/providers/__init__.py +0 -4
  49. agent/providers/anthropic/__init__.py +0 -6
  50. agent/providers/anthropic/api/client.py +0 -360
  51. agent/providers/anthropic/api/logging.py +0 -150
  52. agent/providers/anthropic/api_handler.py +0 -140
  53. agent/providers/anthropic/callbacks/__init__.py +0 -5
  54. agent/providers/anthropic/callbacks/manager.py +0 -65
  55. agent/providers/anthropic/loop.py +0 -568
  56. agent/providers/anthropic/prompts.py +0 -23
  57. agent/providers/anthropic/response_handler.py +0 -226
  58. agent/providers/anthropic/tools/__init__.py +0 -33
  59. agent/providers/anthropic/tools/base.py +0 -88
  60. agent/providers/anthropic/tools/bash.py +0 -66
  61. agent/providers/anthropic/tools/collection.py +0 -34
  62. agent/providers/anthropic/tools/computer.py +0 -396
  63. agent/providers/anthropic/tools/edit.py +0 -326
  64. agent/providers/anthropic/tools/manager.py +0 -54
  65. agent/providers/anthropic/tools/run.py +0 -42
  66. agent/providers/anthropic/types.py +0 -16
  67. agent/providers/anthropic/utils.py +0 -381
  68. agent/providers/omni/__init__.py +0 -8
  69. agent/providers/omni/api_handler.py +0 -42
  70. agent/providers/omni/clients/anthropic.py +0 -103
  71. agent/providers/omni/clients/base.py +0 -35
  72. agent/providers/omni/clients/oaicompat.py +0 -195
  73. agent/providers/omni/clients/ollama.py +0 -122
  74. agent/providers/omni/clients/openai.py +0 -155
  75. agent/providers/omni/clients/utils.py +0 -25
  76. agent/providers/omni/image_utils.py +0 -34
  77. agent/providers/omni/loop.py +0 -990
  78. agent/providers/omni/parser.py +0 -307
  79. agent/providers/omni/prompts.py +0 -64
  80. agent/providers/omni/tools/__init__.py +0 -30
  81. agent/providers/omni/tools/base.py +0 -29
  82. agent/providers/omni/tools/bash.py +0 -74
  83. agent/providers/omni/tools/computer.py +0 -179
  84. agent/providers/omni/tools/manager.py +0 -61
  85. agent/providers/omni/utils.py +0 -236
  86. agent/providers/openai/__init__.py +0 -6
  87. agent/providers/openai/api_handler.py +0 -456
  88. agent/providers/openai/loop.py +0 -472
  89. agent/providers/openai/response_handler.py +0 -205
  90. agent/providers/openai/tools/__init__.py +0 -15
  91. agent/providers/openai/tools/base.py +0 -79
  92. agent/providers/openai/tools/computer.py +0 -326
  93. agent/providers/openai/tools/manager.py +0 -106
  94. agent/providers/openai/types.py +0 -36
  95. agent/providers/openai/utils.py +0 -98
  96. agent/providers/uitars/__init__.py +0 -1
  97. agent/providers/uitars/clients/base.py +0 -35
  98. agent/providers/uitars/clients/mlxvlm.py +0 -263
  99. agent/providers/uitars/clients/oaicompat.py +0 -214
  100. agent/providers/uitars/loop.py +0 -660
  101. agent/providers/uitars/prompts.py +0 -63
  102. agent/providers/uitars/tools/__init__.py +0 -1
  103. agent/providers/uitars/tools/computer.py +0 -283
  104. agent/providers/uitars/tools/manager.py +0 -60
  105. agent/providers/uitars/utils.py +0 -264
  106. agent/telemetry.py +0 -21
  107. agent/ui/__main__.py +0 -15
  108. cua_agent-0.3.2.dist-info/METADATA +0 -295
  109. cua_agent-0.3.2.dist-info/RECORD +0 -87
  110. {cua_agent-0.3.2.dist-info → cua_agent-0.4.0b2.dist-info}/WHEEL +0 -0
  111. {cua_agent-0.3.2.dist-info → cua_agent-0.4.0b2.dist-info}/entry_points.txt +0 -0
@@ -1,226 +0,0 @@
1
- """Response and tool handling for Anthropic provider."""
2
-
3
- import logging
4
- from typing import Any, Dict, List, Tuple, cast
5
-
6
- from anthropic.types.beta import (
7
- BetaMessage,
8
- BetaTextBlock,
9
- BetaContentBlockParam,
10
- )
11
-
12
- from .tools import ToolResult
13
-
14
- logger = logging.getLogger(__name__)
15
-
16
-
17
- class AnthropicResponseHandler:
18
- """Handles Anthropic API responses and tool execution results."""
19
-
20
- def __init__(self, loop):
21
- """Initialize the response handler.
22
-
23
- Args:
24
- loop: Reference to the parent loop instance that provides context
25
- """
26
- self.loop = loop
27
-
28
- async def handle_response(
29
- self, response: BetaMessage, messages: List[Dict[str, Any]]
30
- ) -> Tuple[List[Dict[str, Any]], bool]:
31
- """Handle the Anthropic API response.
32
-
33
- Args:
34
- response: API response
35
- messages: List of messages for context
36
-
37
- Returns:
38
- Tuple containing:
39
- - List of new messages to be added
40
- - Boolean indicating if the loop should continue
41
- """
42
- try:
43
- new_messages = []
44
-
45
- # Convert response to parameter format
46
- response_params = self.response_to_params(response)
47
-
48
- # Collect all existing tool_use IDs from previous messages for validation
49
- existing_tool_use_ids = set()
50
- for msg in messages:
51
- if msg.get("role") == "assistant" and isinstance(msg.get("content"), list):
52
- for block in msg.get("content", []):
53
- if (
54
- isinstance(block, dict)
55
- and block.get("type") == "tool_use"
56
- and "id" in block
57
- ):
58
- existing_tool_use_ids.add(block["id"])
59
-
60
- # Also add new tool_use IDs from the current response
61
- current_tool_use_ids = set()
62
- for block in response_params:
63
- if isinstance(block, dict) and block.get("type") == "tool_use" and "id" in block:
64
- current_tool_use_ids.add(block["id"])
65
- existing_tool_use_ids.add(block["id"])
66
-
67
- logger.info(f"Existing tool_use IDs in conversation: {existing_tool_use_ids}")
68
- logger.info(f"New tool_use IDs in current response: {current_tool_use_ids}")
69
-
70
- # Create assistant message
71
- new_messages.append(
72
- {
73
- "role": "assistant",
74
- "content": response_params,
75
- }
76
- )
77
-
78
- if self.loop.callback_manager is None:
79
- raise RuntimeError(
80
- "Callback manager not initialized. Call initialize_client() first."
81
- )
82
-
83
- # Handle tool use blocks and collect results
84
- tool_result_content = []
85
- for content_block in response_params:
86
- # Notify callback of content
87
- self.loop.callback_manager.on_content(cast(BetaContentBlockParam, content_block))
88
-
89
- # Handle tool use
90
- if content_block.get("type") == "tool_use":
91
- if self.loop.tool_manager is None:
92
- raise RuntimeError(
93
- "Tool manager not initialized. Call initialize_client() first."
94
- )
95
-
96
- # Execute the tool
97
- result = await self.loop.tool_manager.execute_tool(
98
- name=content_block["name"],
99
- tool_input=cast(Dict[str, Any], content_block["input"]),
100
- )
101
-
102
- # Verify the tool_use ID exists in the conversation (which it should now)
103
- tool_use_id = content_block["id"]
104
- if tool_use_id in existing_tool_use_ids:
105
- # Create tool result and add to content
106
- tool_result = self.make_tool_result(cast(ToolResult, result), tool_use_id)
107
- tool_result_content.append(tool_result)
108
-
109
- # Notify callback of tool result
110
- self.loop.callback_manager.on_tool_result(
111
- cast(ToolResult, result), content_block["id"]
112
- )
113
- else:
114
- logger.warning(
115
- f"Tool use ID {tool_use_id} not found in previous messages. Skipping tool result."
116
- )
117
-
118
- # If no tool results, we're done
119
- if not tool_result_content:
120
- # Signal completion
121
- self.loop.callback_manager.on_content({"type": "text", "text": "<DONE>"})
122
- return new_messages, False
123
-
124
- # Add tool results as user message
125
- new_messages.append({"content": tool_result_content, "role": "user"})
126
- return new_messages, True
127
-
128
- except Exception as e:
129
- logger.error(f"Error handling response: {str(e)}")
130
- new_messages.append(
131
- {
132
- "role": "assistant",
133
- "content": f"Error: {str(e)}",
134
- }
135
- )
136
- return new_messages, False
137
-
138
- def response_to_params(
139
- self,
140
- response: BetaMessage,
141
- ) -> List[Dict[str, Any]]:
142
- """Convert API response to message parameters.
143
-
144
- Args:
145
- response: API response message
146
-
147
- Returns:
148
- List of content blocks
149
- """
150
- result = []
151
- for block in response.content:
152
- if isinstance(block, BetaTextBlock):
153
- result.append({"type": "text", "text": block.text})
154
- else:
155
- result.append(cast(Dict[str, Any], block.model_dump()))
156
- return result
157
-
158
- def make_tool_result(self, result: ToolResult, tool_use_id: str) -> Dict[str, Any]:
159
- """Convert a tool result to API format.
160
-
161
- Args:
162
- result: Tool execution result
163
- tool_use_id: ID of the tool use
164
-
165
- Returns:
166
- Formatted tool result
167
- """
168
- if result.content:
169
- return {
170
- "type": "tool_result",
171
- "content": result.content,
172
- "tool_use_id": tool_use_id,
173
- "is_error": bool(result.error),
174
- }
175
-
176
- tool_result_content = []
177
- is_error = False
178
-
179
- if result.error:
180
- is_error = True
181
- tool_result_content = [
182
- {
183
- "type": "text",
184
- "text": self.maybe_prepend_system_tool_result(result, result.error),
185
- }
186
- ]
187
- else:
188
- if result.output:
189
- tool_result_content.append(
190
- {
191
- "type": "text",
192
- "text": self.maybe_prepend_system_tool_result(result, result.output),
193
- }
194
- )
195
- if result.base64_image:
196
- tool_result_content.append(
197
- {
198
- "type": "image",
199
- "source": {
200
- "type": "base64",
201
- "media_type": "image/png",
202
- "data": result.base64_image,
203
- },
204
- }
205
- )
206
-
207
- return {
208
- "type": "tool_result",
209
- "content": tool_result_content,
210
- "tool_use_id": tool_use_id,
211
- "is_error": is_error,
212
- }
213
-
214
- def maybe_prepend_system_tool_result(self, result: ToolResult, result_text: str) -> str:
215
- """Prepend system information to tool result if available.
216
-
217
- Args:
218
- result: Tool execution result
219
- result_text: Text to prepend to
220
-
221
- Returns:
222
- Text with system information prepended if available
223
- """
224
- if result.system:
225
- result_text = f"<s>{result.system}</s>\n{result_text}"
226
- return result_text
@@ -1,33 +0,0 @@
1
- """Anthropic-specific tools for agent."""
2
-
3
- from .base import (
4
- BaseAnthropicTool,
5
- ToolResult,
6
- ToolError,
7
- ToolFailure,
8
- CLIResult,
9
- AnthropicToolResult,
10
- AnthropicToolError,
11
- AnthropicToolFailure,
12
- AnthropicCLIResult,
13
- )
14
- from .bash import BashTool
15
- from .computer import ComputerTool
16
- from .edit import EditTool
17
- from .manager import ToolManager
18
-
19
- __all__ = [
20
- "BaseAnthropicTool",
21
- "ToolResult",
22
- "ToolError",
23
- "ToolFailure",
24
- "CLIResult",
25
- "AnthropicToolResult",
26
- "AnthropicToolError",
27
- "AnthropicToolFailure",
28
- "AnthropicCLIResult",
29
- "BashTool",
30
- "ComputerTool",
31
- "EditTool",
32
- "ToolManager",
33
- ]
@@ -1,88 +0,0 @@
1
- """Anthropic-specific tool base classes."""
2
-
3
- from abc import ABCMeta, abstractmethod
4
- from dataclasses import dataclass, fields, replace
5
- from typing import Any, Dict
6
-
7
- from anthropic.types.beta import BetaToolUnionParam
8
-
9
- from ....core.tools.base import BaseTool
10
-
11
-
12
- class BaseAnthropicTool(BaseTool, metaclass=ABCMeta):
13
- """Abstract base class for Anthropic-defined tools."""
14
-
15
- def __init__(self):
16
- """Initialize the base Anthropic tool."""
17
- # No specific initialization needed yet, but included for future extensibility
18
- pass
19
-
20
- @abstractmethod
21
- async def __call__(self, **kwargs) -> Any:
22
- """Executes the tool with the given arguments."""
23
- ...
24
-
25
- @abstractmethod
26
- def to_params(self) -> Dict[str, Any]:
27
- """Convert tool to Anthropic-specific API parameters.
28
-
29
- Returns:
30
- Dictionary with tool parameters for Anthropic API
31
- """
32
- raise NotImplementedError
33
-
34
-
35
- @dataclass(kw_only=True, frozen=True)
36
- class ToolResult:
37
- """Represents the result of a tool execution."""
38
-
39
- output: str | None = None
40
- error: str | None = None
41
- base64_image: str | None = None
42
- system: str | None = None
43
- content: list[dict] | None = None
44
-
45
- def __bool__(self):
46
- return any(getattr(self, field.name) for field in fields(self))
47
-
48
- def __add__(self, other: "ToolResult"):
49
- def combine_fields(field: str | None, other_field: str | None, concatenate: bool = True):
50
- if field and other_field:
51
- if concatenate:
52
- return field + other_field
53
- raise ValueError("Cannot combine tool results")
54
- return field or other_field
55
-
56
- return ToolResult(
57
- output=combine_fields(self.output, other.output),
58
- error=combine_fields(self.error, other.error),
59
- base64_image=combine_fields(self.base64_image, other.base64_image, False),
60
- system=combine_fields(self.system, other.system),
61
- content=self.content or other.content, # Use first non-None content
62
- )
63
-
64
- def replace(self, **kwargs):
65
- """Returns a new ToolResult with the given fields replaced."""
66
- return replace(self, **kwargs)
67
-
68
-
69
- class CLIResult(ToolResult):
70
- """A ToolResult that can be rendered as a CLI output."""
71
-
72
-
73
- class ToolFailure(ToolResult):
74
- """A ToolResult that represents a failure."""
75
-
76
-
77
- class ToolError(Exception):
78
- """Raised when a tool encounters an error."""
79
-
80
- def __init__(self, message):
81
- self.message = message
82
-
83
-
84
- # Re-export the core tool classes with Anthropic-specific names for backward compatibility
85
- AnthropicToolResult = ToolResult
86
- AnthropicToolError = ToolError
87
- AnthropicToolFailure = ToolFailure
88
- AnthropicCLIResult = CLIResult
@@ -1,66 +0,0 @@
1
- import asyncio
2
- import os
3
- from typing import ClassVar, Literal, Dict, Any
4
- from computer.computer import Computer
5
-
6
- from .base import BaseAnthropicTool, CLIResult, ToolError, ToolResult
7
- from ....core.tools.bash import BaseBashTool
8
-
9
-
10
- class BashTool(BaseBashTool, BaseAnthropicTool):
11
- """
12
- A tool that allows the agent to run bash commands.
13
- The tool parameters are defined by Anthropic and are not editable.
14
- """
15
-
16
- name: ClassVar[Literal["bash"]] = "bash"
17
- api_type: ClassVar[Literal["bash_20250124"]] = "bash_20250124"
18
- _timeout: float = 120.0 # seconds
19
-
20
- def __init__(self, computer: Computer):
21
- """Initialize the bash tool.
22
-
23
- Args:
24
- computer: Computer instance for executing commands
25
- """
26
- # Initialize the base bash tool first
27
- BaseBashTool.__init__(self, computer)
28
- # Then initialize the Anthropic tool
29
- BaseAnthropicTool.__init__(self)
30
- # Initialize bash session
31
-
32
- async def __call__(self, command: str | None = None, restart: bool = False, **kwargs):
33
- """Execute a bash command.
34
-
35
- Args:
36
- command: The command to execute
37
- restart: Whether to restart the shell (not used with computer interface)
38
-
39
- Returns:
40
- Tool execution result
41
-
42
- Raises:
43
- ToolError: If command execution fails
44
- """
45
- if restart:
46
- return ToolResult(system="Restart not needed with computer interface.")
47
-
48
- if command is None:
49
- raise ToolError("no command provided.")
50
-
51
- try:
52
- async with asyncio.timeout(self._timeout):
53
- result = await self.computer.interface.run_command(command)
54
- return CLIResult(output=result.stdout or "", error=result.stderr or "")
55
- except asyncio.TimeoutError as e:
56
- raise ToolError(f"Command timed out after {self._timeout} seconds") from e
57
- except Exception as e:
58
- raise ToolError(f"Failed to execute command: {str(e)}")
59
-
60
- def to_params(self) -> Dict[str, Any]:
61
- """Convert tool to API parameters.
62
-
63
- Returns:
64
- Dictionary with tool parameters
65
- """
66
- return {"name": self.name, "type": self.api_type}
@@ -1,34 +0,0 @@
1
- """Collection classes for managing multiple tools."""
2
-
3
- from typing import Any, cast
4
-
5
- from anthropic.types.beta import BetaToolUnionParam
6
-
7
- from .base import (
8
- BaseAnthropicTool,
9
- ToolError,
10
- ToolFailure,
11
- ToolResult,
12
- )
13
-
14
-
15
- class ToolCollection:
16
- """A collection of anthropic-defined tools."""
17
-
18
- def __init__(self, *tools: BaseAnthropicTool):
19
- self.tools = tools
20
- self.tool_map = {tool.to_params()["name"]: tool for tool in tools}
21
-
22
- def to_params(
23
- self,
24
- ) -> list[BetaToolUnionParam]:
25
- return cast(list[BetaToolUnionParam], [tool.to_params() for tool in self.tools])
26
-
27
- async def run(self, *, name: str, tool_input: dict[str, Any]) -> ToolResult:
28
- tool = self.tool_map.get(name)
29
- if not tool:
30
- return ToolFailure(error=f"Tool {name} is invalid")
31
- try:
32
- return await tool(**tool_input)
33
- except ToolError as e:
34
- return ToolFailure(error=e.message)