cua-agent 0.3.2__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. 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.0b1.dist-info}/WHEEL +0 -0
  111. {cua_agent-0.3.2.dist-info → cua_agent-0.4.0b1.dist-info}/entry_points.txt +0 -0
@@ -1,568 +0,0 @@
1
- """Anthropic-specific agent loop implementation."""
2
-
3
- import logging
4
- import asyncio
5
- from typing import Any, AsyncGenerator, Dict, List, Optional, Tuple, cast
6
- from anthropic.types.beta import (
7
- BetaMessage,
8
- BetaMessageParam,
9
- BetaTextBlock,
10
- BetaContentBlockParam,
11
- )
12
- import base64
13
- from datetime import datetime
14
-
15
- # Computer
16
- from computer import Computer
17
-
18
- # Base imports
19
- from ...core.base import BaseLoop
20
- from ...core.messages import StandardMessageManager, ImageRetentionConfig
21
- from ...core.types import AgentResponse
22
-
23
- # Anthropic provider-specific imports
24
- from .api.client import AnthropicClientFactory, BaseAnthropicClient
25
- from .tools.manager import ToolManager
26
- from .prompts import SYSTEM_PROMPT
27
- from .types import LLMProvider
28
- from .tools import ToolResult
29
- from .utils import to_anthropic_format, to_agent_response_format
30
-
31
- # Import the new modules we created
32
- from .api_handler import AnthropicAPIHandler
33
- from .response_handler import AnthropicResponseHandler
34
- from .callbacks.manager import CallbackManager
35
-
36
- # Constants
37
- COMPUTER_USE_BETA_FLAG = "computer-use-2025-01-24"
38
- PROMPT_CACHING_BETA_FLAG = "prompt-caching-2024-07-31"
39
-
40
- logger = logging.getLogger(__name__)
41
-
42
-
43
- class AnthropicLoop(BaseLoop):
44
- """Anthropic-specific implementation of the agent loop.
45
-
46
- This class extends BaseLoop to provide specialized support for Anthropic's Claude models
47
- with their unique tool-use capabilities, custom message formatting, and
48
- callback-driven approach to handling responses.
49
- """
50
-
51
- ###########################################
52
- # INITIALIZATION AND CONFIGURATION
53
- ###########################################
54
-
55
- def __init__(
56
- self,
57
- api_key: str,
58
- computer: Computer,
59
- model: str = "claude-3-7-sonnet-20250219",
60
- only_n_most_recent_images: Optional[int] = 2,
61
- base_dir: Optional[str] = "trajectories",
62
- max_retries: int = 3,
63
- retry_delay: float = 1.0,
64
- save_trajectory: bool = True,
65
- **kwargs,
66
- ):
67
- """Initialize the Anthropic loop.
68
-
69
- Args:
70
- api_key: Anthropic API key
71
- model: Model name (fixed to claude-3-7-sonnet-20250219)
72
- computer: Computer instance
73
- only_n_most_recent_images: Maximum number of recent screenshots to include in API requests
74
- base_dir: Base directory for saving experiment data
75
- max_retries: Maximum number of retries for API calls
76
- retry_delay: Delay between retries in seconds
77
- save_trajectory: Whether to save trajectory data
78
- """
79
- # Initialize base class with core config
80
- super().__init__(
81
- computer=computer,
82
- model=model,
83
- api_key=api_key,
84
- max_retries=max_retries,
85
- retry_delay=retry_delay,
86
- base_dir=base_dir,
87
- save_trajectory=save_trajectory,
88
- only_n_most_recent_images=only_n_most_recent_images,
89
- **kwargs,
90
- )
91
-
92
- # Initialize message manager
93
- self.message_manager = StandardMessageManager(
94
- config=ImageRetentionConfig(num_images_to_keep=only_n_most_recent_images)
95
- )
96
-
97
- # Anthropic-specific attributes
98
- self.provider = LLMProvider.ANTHROPIC
99
- self.client = None
100
- self.retry_count = 0
101
- self.tool_manager = None
102
- self.callback_manager = None
103
- self.queue = asyncio.Queue() # Initialize queue
104
- self.loop_task = None # Store the loop task for cancellation
105
-
106
- # Initialize handlers
107
- self.api_handler = AnthropicAPIHandler(self)
108
- self.response_handler = AnthropicResponseHandler(self)
109
-
110
- ###########################################
111
- # CLIENT INITIALIZATION - IMPLEMENTING ABSTRACT METHOD
112
- ###########################################
113
-
114
- async def initialize_client(self) -> None:
115
- """Initialize the Anthropic API client and tools.
116
-
117
- Implements abstract method from BaseLoop to set up the Anthropic-specific
118
- client, tool manager, message manager, and callback handlers.
119
- """
120
- try:
121
- logger.info(f"Initializing Anthropic client with model {self.model}...")
122
-
123
- # Initialize client
124
- self.client = AnthropicClientFactory.create_client(
125
- provider=self.provider, api_key=self.api_key, model=self.model
126
- )
127
-
128
- # Initialize callback manager with our callback handlers
129
- self.callback_manager = CallbackManager(
130
- content_callback=self._handle_content,
131
- tool_callback=self._handle_tool_result,
132
- api_callback=self._handle_api_interaction,
133
- )
134
-
135
- # Initialize tool manager
136
- self.tool_manager = ToolManager(self.computer)
137
- await self.tool_manager.initialize()
138
-
139
- logger.info(f"Initialized Anthropic client with model {self.model}")
140
- except Exception as e:
141
- logger.error(f"Error initializing Anthropic client: {str(e)}")
142
- self.client = None
143
- raise RuntimeError(f"Failed to initialize Anthropic client: {str(e)}")
144
-
145
- ###########################################
146
- # MAIN LOOP - IMPLEMENTING ABSTRACT METHOD
147
- ###########################################
148
-
149
- async def run(self, messages: List[Dict[str, Any]]) -> AsyncGenerator[AgentResponse, None]:
150
- """Run the agent loop with provided messages.
151
-
152
- Args:
153
- messages: List of message objects in standard OpenAI format
154
-
155
- Yields:
156
- Agent response format
157
- """
158
- try:
159
- logger.info("Starting Anthropic loop run")
160
-
161
- # Create queue for response streaming
162
- queue = asyncio.Queue()
163
-
164
- # Ensure client is initialized
165
- if self.client is None or self.tool_manager is None:
166
- logger.info("Initializing client...")
167
- await self.initialize_client()
168
- if self.client is None:
169
- raise RuntimeError("Failed to initialize client")
170
- logger.info("Client initialized successfully")
171
-
172
- # Start loop in background task
173
- self.loop_task = asyncio.create_task(self._run_loop(queue, messages))
174
-
175
- # Process and yield messages as they arrive
176
- while True:
177
- try:
178
- item = await queue.get()
179
- if item is None: # Stop signal
180
- break
181
- yield item
182
- queue.task_done()
183
- except Exception as e:
184
- logger.error(f"Error processing queue item: {str(e)}")
185
- continue
186
-
187
- # Wait for loop to complete
188
- await self.loop_task
189
-
190
- # Send completion message
191
- yield {
192
- "role": "assistant",
193
- "content": "Task completed successfully.",
194
- "metadata": {"title": "✅ Complete"},
195
- }
196
-
197
- except Exception as e:
198
- logger.error(f"Error executing task: {str(e)}")
199
- yield {
200
- "role": "assistant",
201
- "content": f"Error: {str(e)}",
202
- "metadata": {"title": "❌ Error"},
203
- }
204
-
205
- async def cancel(self) -> None:
206
- """Cancel the currently running agent loop task.
207
-
208
- This method stops the ongoing processing in the agent loop
209
- by cancelling the loop_task if it exists and is running.
210
- """
211
- if self.loop_task and not self.loop_task.done():
212
- logger.info("Cancelling Anthropic loop task")
213
- self.loop_task.cancel()
214
- try:
215
- # Wait for the task to be cancelled with a timeout
216
- await asyncio.wait_for(self.loop_task, timeout=2.0)
217
- except asyncio.TimeoutError:
218
- logger.warning("Timeout while waiting for loop task to cancel")
219
- except asyncio.CancelledError:
220
- logger.info("Loop task cancelled successfully")
221
- except Exception as e:
222
- logger.error(f"Error while cancelling loop task: {str(e)}")
223
- finally:
224
- # Put None in the queue to signal any waiting consumers to stop
225
- await self.queue.put(None)
226
- logger.info("Anthropic loop task cancelled")
227
- else:
228
- logger.info("No active Anthropic loop task to cancel")
229
-
230
- ###########################################
231
- # AGENT LOOP IMPLEMENTATION
232
- ###########################################
233
-
234
- async def _run_loop(self, queue: asyncio.Queue, messages: List[Dict[str, Any]]) -> None:
235
- """Run the agent loop with provided messages.
236
-
237
- Args:
238
- queue: Queue for response streaming
239
- messages: List of messages in standard OpenAI format
240
- """
241
- try:
242
- while True:
243
- # Capture screenshot
244
- try:
245
- # Take screenshot - always returns raw PNG bytes
246
- screenshot = await self.computer.interface.screenshot()
247
- logger.info("Screenshot captured successfully")
248
-
249
- # Convert PNG bytes to base64
250
- base64_image = base64.b64encode(screenshot).decode("utf-8")
251
- logger.info(f"Screenshot converted to base64 (size: {len(base64_image)} bytes)")
252
-
253
- # Save screenshot if requested
254
- if self.save_trajectory and self.experiment_manager:
255
- try:
256
- self._save_screenshot(base64_image, action_type="state")
257
- logger.info("Screenshot saved to trajectory")
258
- except Exception as e:
259
- logger.error(f"Error saving screenshot: {str(e)}")
260
-
261
- # Create screenshot message
262
- screen_info_msg = {
263
- "role": "user",
264
- "content": [
265
- {
266
- "type": "image",
267
- "source": {
268
- "type": "base64",
269
- "media_type": "image/png",
270
- "data": base64_image,
271
- },
272
- }
273
- ],
274
- }
275
- # Add screenshot to messages
276
- messages.append(screen_info_msg)
277
- logger.info("Screenshot message added to conversation")
278
-
279
- except Exception as e:
280
- logger.error(f"Error capturing or processing screenshot: {str(e)}")
281
- raise
282
-
283
- # Create new turn directory for this API call
284
- self._create_turn_dir()
285
-
286
-
287
- # Apply image retention policy
288
- self.message_manager.messages = messages.copy()
289
- prepared_messages = self.message_manager.get_messages()
290
- # Convert standard messages to Anthropic format using utility function
291
- anthropic_messages, system_content = to_anthropic_format(prepared_messages)
292
-
293
- # Use API handler to make API call with Anthropic format
294
- response = await self.api_handler.make_api_call(
295
- messages=cast(List[BetaMessageParam], anthropic_messages),
296
- system_prompt=system_content or SYSTEM_PROMPT,
297
- )
298
-
299
- # Use response handler to handle the response and get new messages
300
- new_messages, should_continue = await self.response_handler.handle_response(
301
- response, messages
302
- )
303
-
304
- # Add new messages to the parent's message history
305
- messages.extend(new_messages)
306
-
307
- openai_compatible_response = await to_agent_response_format(
308
- response,
309
- messages,
310
- model=self.model,
311
- )
312
- # Log standardized response for ease of parsing
313
- self._log_api_call("agent_response", request=None, response=openai_compatible_response)
314
- await queue.put(openai_compatible_response)
315
-
316
- if not should_continue:
317
- break
318
-
319
- # Signal completion
320
- await queue.put(None)
321
-
322
- except Exception as e:
323
- logger.error(f"Error in _run_loop: {str(e)}")
324
- await queue.put(
325
- {
326
- "role": "assistant",
327
- "content": f"Error in agent loop: {str(e)}",
328
- "metadata": {"title": "❌ Error"},
329
- }
330
- )
331
- await queue.put(None)
332
-
333
- ###########################################
334
- # RESPONSE AND CALLBACK HANDLING
335
- ###########################################
336
-
337
- async def _handle_response(self, response: BetaMessage, messages: List[Dict[str, Any]]) -> bool:
338
- """Handle a response from the Anthropic API.
339
-
340
- Args:
341
- response: The response from the Anthropic API
342
- messages: The message history
343
-
344
- Returns:
345
- bool: Whether to continue the conversation
346
- """
347
- try:
348
- # Convert response to standard format
349
- openai_compatible_response = await to_agent_response_format(
350
- response,
351
- messages,
352
- model=self.model,
353
- )
354
-
355
- # Put the response on the queue
356
- await self.queue.put(openai_compatible_response)
357
-
358
- if self.callback_manager is None:
359
- raise RuntimeError(
360
- "Callback manager not initialized. Call initialize_client() first."
361
- )
362
-
363
- # Handle tool use blocks and collect ALL results before adding to messages
364
- tool_result_content = []
365
- has_tool_use = False
366
-
367
- for content_block in response.content:
368
- # Notify callback of content
369
- self.callback_manager.on_content(cast(BetaContentBlockParam, content_block))
370
-
371
- # Handle tool use - carefully check and access attributes
372
- if hasattr(content_block, "type") and content_block.type == "tool_use":
373
- has_tool_use = True
374
- if self.tool_manager is None:
375
- raise RuntimeError(
376
- "Tool manager not initialized. Call initialize_client() first."
377
- )
378
-
379
- # Safely get attributes
380
- tool_name = getattr(content_block, "name", "")
381
- tool_input = getattr(content_block, "input", {})
382
- tool_id = getattr(content_block, "id", "")
383
-
384
- result = await self.tool_manager.execute_tool(
385
- name=tool_name,
386
- tool_input=cast(Dict[str, Any], tool_input),
387
- )
388
-
389
- # Create tool result
390
- tool_result = self._make_tool_result(cast(ToolResult, result), tool_id)
391
- tool_result_content.append(tool_result)
392
-
393
- # Notify callback of tool result
394
- self.callback_manager.on_tool_result(cast(ToolResult, result), tool_id)
395
-
396
- # If we had any tool_use blocks, we MUST add the tool_result message
397
- # even if there were errors or no actual results
398
- if has_tool_use:
399
- # If somehow we have no tool results but had tool uses, add synthetic error results
400
- if not tool_result_content:
401
- logger.warning(
402
- "Had tool uses but no tool results, adding synthetic error results"
403
- )
404
- for content_block in response.content:
405
- if hasattr(content_block, "type") and content_block.type == "tool_use":
406
- tool_id = getattr(content_block, "id", "")
407
- if tool_id:
408
- tool_result_content.append(
409
- {
410
- "type": "tool_result",
411
- "tool_use_id": tool_id,
412
- "content": {
413
- "type": "error",
414
- "text": "Tool execution was skipped or failed",
415
- },
416
- "is_error": True,
417
- }
418
- )
419
-
420
- # Add ALL tool results as a SINGLE user message
421
- messages.append({"role": "user", "content": tool_result_content})
422
- return True
423
- else:
424
- # No tool uses, we're done
425
- self.callback_manager.on_content({"type": "text", "text": "<DONE>"})
426
- return False
427
-
428
- except Exception as e:
429
- logger.error(f"Error handling response: {str(e)}")
430
- messages.append(
431
- {
432
- "role": "assistant",
433
- "content": f"Error: {str(e)}",
434
- }
435
- )
436
- return False
437
-
438
- def _response_to_blocks(self, response: BetaMessage) -> List[Dict[str, Any]]:
439
- """Convert Anthropic API response to standard blocks format.
440
-
441
- Args:
442
- response: API response message
443
-
444
- Returns:
445
- List of content blocks in standard format
446
- """
447
- result = []
448
- for block in response.content:
449
- if isinstance(block, BetaTextBlock):
450
- result.append({"type": "text", "text": block.text})
451
- elif hasattr(block, "type") and block.type == "tool_use":
452
- # Safely access attributes after confirming it's a tool_use
453
- result.append(
454
- {
455
- "type": "tool_use",
456
- "id": getattr(block, "id", ""),
457
- "name": getattr(block, "name", ""),
458
- "input": getattr(block, "input", {}),
459
- }
460
- )
461
- else:
462
- # For other block types, convert to dict
463
- block_dict = {}
464
- for key, value in vars(block).items():
465
- if not key.startswith("_"):
466
- block_dict[key] = value
467
- result.append(block_dict)
468
-
469
- return result
470
-
471
- def _make_tool_result(self, result: ToolResult, tool_use_id: str) -> Dict[str, Any]:
472
- """Convert a tool result to standard format.
473
-
474
- Args:
475
- result: Tool execution result
476
- tool_use_id: ID of the tool use
477
-
478
- Returns:
479
- Formatted tool result
480
- """
481
- if result.content:
482
- return {
483
- "type": "tool_result",
484
- "content": result.content,
485
- "tool_use_id": tool_use_id,
486
- "is_error": bool(result.error),
487
- }
488
-
489
- tool_result_content = []
490
- is_error = False
491
-
492
- if result.error:
493
- is_error = True
494
- tool_result_content = [
495
- {
496
- "type": "text",
497
- "text": self._maybe_prepend_system_tool_result(result, result.error),
498
- }
499
- ]
500
- else:
501
- if result.output:
502
- tool_result_content.append(
503
- {
504
- "type": "text",
505
- "text": self._maybe_prepend_system_tool_result(result, result.output),
506
- }
507
- )
508
- if result.base64_image:
509
- tool_result_content.append(
510
- {
511
- "type": "image_url",
512
- "image_url": {"url": f"data:image/png;base64,{result.base64_image}"},
513
- }
514
- )
515
-
516
- return {
517
- "type": "tool_result",
518
- "content": tool_result_content,
519
- "tool_use_id": tool_use_id,
520
- "is_error": is_error,
521
- }
522
-
523
- def _maybe_prepend_system_tool_result(self, result: ToolResult, result_text: str) -> str:
524
- """Prepend system information to tool result if available.
525
-
526
- Args:
527
- result: Tool execution result
528
- result_text: Text to prepend to
529
-
530
- Returns:
531
- Text with system information prepended if available
532
- """
533
- if result.system:
534
- result_text = f"<s>{result.system}</s>\n{result_text}"
535
- return result_text
536
-
537
- ###########################################
538
- # CALLBACK HANDLERS
539
- ###########################################
540
-
541
- def _handle_content(self, content):
542
- """Handle content updates from the assistant."""
543
- if content.get("type") == "text":
544
- text = content.get("text", "")
545
- if text == "<DONE>":
546
- return
547
- logger.info(f"Assistant: {text}")
548
-
549
- def _handle_tool_result(self, result, tool_id):
550
- """Handle tool execution results."""
551
- if result.error:
552
- logger.error(f"Tool {tool_id} error: {result.error}")
553
- else:
554
- logger.info(f"Tool {tool_id} output: {result.output}")
555
-
556
- def _handle_api_interaction(
557
- self, request: Any, response: Any, error: Optional[Exception]
558
- ) -> None:
559
- """Handle API interactions."""
560
- if error:
561
- logger.error(f"API error: {error}")
562
- self._log_api_call("error", request, error=error)
563
- else:
564
- logger.debug(f"API request: {request}")
565
- if response:
566
- self._log_api_call("response", request, response)
567
- else:
568
- self._log_api_call("request", request)
@@ -1,23 +0,0 @@
1
- """System prompts for Anthropic provider."""
2
-
3
- from datetime import datetime
4
- import platform
5
-
6
- today = datetime.today()
7
- today = f"{today.strftime('%A, %B')} {today.day}, {today.year}"
8
-
9
- SYSTEM_PROMPT = f"""<SYSTEM_CAPABILITY>
10
- * You are utilising a macOS virtual machine using ARM architecture with internet access and Safari as default browser.
11
- * You can feel free to install macOS applications with your bash tool. Use curl instead of wget.
12
- * Using bash tool you can start GUI applications. GUI apps run with bash tool will appear within your desktop environment, but they may take some time to appear. Take a screenshot to confirm it did.
13
- * When using your bash tool with commands that are expected to output very large quantities of text, redirect into a tmp file and use str_replace_editor or `grep -n -B <lines before> -A <lines after> <query> <filename>` to confirm output.
14
- * When viewing a page it can be helpful to zoom out so that you can see everything on the page. Either that, or make sure you scroll down to see everything before deciding something isn't available.
15
- * When using your computer function calls, they take a while to run and send back to you. Where possible/feasible, try to chain multiple of these calls all into one function calls request.
16
- * The current date is {today}.
17
- </SYSTEM_CAPABILITY>
18
-
19
- <IMPORTANT>
20
- * Plan at maximum 1 step each time, and evaluate the result of each step before proceeding. Hold back if you're not sure about the result of the step.
21
- * If you're not sure about the location of an application, use start the app using the bash tool.
22
- * If the item you are looking at is a pdf, if after taking a single screenshot of the pdf it seems that you want to read the entire document instead of trying to continue to read the pdf from your screenshots + navigation, determine the URL, use curl to download the pdf, install and use pdftotext to convert it to a text file, and then read that text file directly with your StrReplaceEditTool.
23
- </IMPORTANT>"""