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.
- agent/__init__.py +15 -51
- agent/__main__.py +21 -0
- agent/adapters/__init__.py +9 -0
- agent/adapters/huggingfacelocal_adapter.py +216 -0
- agent/agent.py +577 -0
- agent/callbacks/__init__.py +17 -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/trajectory_saver.py +305 -0
- agent/cli.py +290 -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/types.py +79 -0
- agent/ui/__init__.py +7 -1
- agent/ui/gradio/__init__.py +6 -19
- agent/ui/gradio/app.py +80 -1299
- agent/ui/gradio/ui_components.py +703 -0
- cua_agent-0.4.0b1.dist-info/METADATA +424 -0
- cua_agent-0.4.0b1.dist-info/RECORD +30 -0
- {cua_agent-0.3.1.dist-info → cua_agent-0.4.0b1.dist-info}/WHEEL +1 -1
- 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 -367
- 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
- agent/telemetry.py +0 -21
- agent/ui/__main__.py +0 -15
- cua_agent-0.3.1.dist-info/METADATA +0 -295
- cua_agent-0.3.1.dist-info/RECORD +0 -87
- {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)
|