cua-agent 0.3.1__py3-none-any.whl → 0.4.0b1__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 +216 -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.0b1.dist-info/METADATA +424 -0
  28. cua_agent-0.4.0b1.dist-info/RECORD +30 -0
  29. {cua_agent-0.3.1.dist-info → cua_agent-0.4.0b1.dist-info}/WHEEL +1 -1
  30. agent/core/__init__.py +0 -27
  31. agent/core/agent.py +0 -210
  32. agent/core/base.py +0 -217
  33. agent/core/callbacks.py +0 -200
  34. agent/core/experiment.py +0 -249
  35. agent/core/factory.py +0 -122
  36. agent/core/messages.py +0 -332
  37. agent/core/provider_config.py +0 -21
  38. agent/core/telemetry.py +0 -142
  39. agent/core/tools/__init__.py +0 -21
  40. agent/core/tools/base.py +0 -74
  41. agent/core/tools/bash.py +0 -52
  42. agent/core/tools/collection.py +0 -46
  43. agent/core/tools/computer.py +0 -113
  44. agent/core/tools/edit.py +0 -67
  45. agent/core/tools/manager.py +0 -56
  46. agent/core/tools.py +0 -32
  47. agent/core/types.py +0 -88
  48. agent/core/visualization.py +0 -197
  49. agent/providers/__init__.py +0 -4
  50. agent/providers/anthropic/__init__.py +0 -6
  51. agent/providers/anthropic/api/client.py +0 -360
  52. agent/providers/anthropic/api/logging.py +0 -150
  53. agent/providers/anthropic/api_handler.py +0 -140
  54. agent/providers/anthropic/callbacks/__init__.py +0 -5
  55. agent/providers/anthropic/callbacks/manager.py +0 -65
  56. agent/providers/anthropic/loop.py +0 -568
  57. agent/providers/anthropic/prompts.py +0 -23
  58. agent/providers/anthropic/response_handler.py +0 -226
  59. agent/providers/anthropic/tools/__init__.py +0 -33
  60. agent/providers/anthropic/tools/base.py +0 -88
  61. agent/providers/anthropic/tools/bash.py +0 -66
  62. agent/providers/anthropic/tools/collection.py +0 -34
  63. agent/providers/anthropic/tools/computer.py +0 -396
  64. agent/providers/anthropic/tools/edit.py +0 -326
  65. agent/providers/anthropic/tools/manager.py +0 -54
  66. agent/providers/anthropic/tools/run.py +0 -42
  67. agent/providers/anthropic/types.py +0 -16
  68. agent/providers/anthropic/utils.py +0 -367
  69. agent/providers/omni/__init__.py +0 -8
  70. agent/providers/omni/api_handler.py +0 -42
  71. agent/providers/omni/clients/anthropic.py +0 -103
  72. agent/providers/omni/clients/base.py +0 -35
  73. agent/providers/omni/clients/oaicompat.py +0 -195
  74. agent/providers/omni/clients/ollama.py +0 -122
  75. agent/providers/omni/clients/openai.py +0 -155
  76. agent/providers/omni/clients/utils.py +0 -25
  77. agent/providers/omni/image_utils.py +0 -34
  78. agent/providers/omni/loop.py +0 -990
  79. agent/providers/omni/parser.py +0 -307
  80. agent/providers/omni/prompts.py +0 -64
  81. agent/providers/omni/tools/__init__.py +0 -30
  82. agent/providers/omni/tools/base.py +0 -29
  83. agent/providers/omni/tools/bash.py +0 -74
  84. agent/providers/omni/tools/computer.py +0 -179
  85. agent/providers/omni/tools/manager.py +0 -61
  86. agent/providers/omni/utils.py +0 -236
  87. agent/providers/openai/__init__.py +0 -6
  88. agent/providers/openai/api_handler.py +0 -456
  89. agent/providers/openai/loop.py +0 -472
  90. agent/providers/openai/response_handler.py +0 -205
  91. agent/providers/openai/tools/__init__.py +0 -15
  92. agent/providers/openai/tools/base.py +0 -79
  93. agent/providers/openai/tools/computer.py +0 -326
  94. agent/providers/openai/tools/manager.py +0 -106
  95. agent/providers/openai/types.py +0 -36
  96. agent/providers/openai/utils.py +0 -98
  97. agent/providers/uitars/__init__.py +0 -1
  98. agent/providers/uitars/clients/base.py +0 -35
  99. agent/providers/uitars/clients/mlxvlm.py +0 -263
  100. agent/providers/uitars/clients/oaicompat.py +0 -214
  101. agent/providers/uitars/loop.py +0 -660
  102. agent/providers/uitars/prompts.py +0 -63
  103. agent/providers/uitars/tools/__init__.py +0 -1
  104. agent/providers/uitars/tools/computer.py +0 -283
  105. agent/providers/uitars/tools/manager.py +0 -60
  106. agent/providers/uitars/utils.py +0 -264
  107. agent/telemetry.py +0 -21
  108. agent/ui/__main__.py +0 -15
  109. cua_agent-0.3.1.dist-info/METADATA +0 -295
  110. cua_agent-0.3.1.dist-info/RECORD +0 -87
  111. {cua_agent-0.3.1.dist-info → cua_agent-0.4.0b1.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)