lybic-guiagents 0.1.0__py3-none-any.whl → 0.2.1__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 lybic-guiagents might be problematic. Click here for more details.

Files changed (38) hide show
  1. gui_agents/__init__.py +63 -0
  2. gui_agents/agents/Action.py +3 -3
  3. gui_agents/agents/Backend/ADBBackend.py +62 -0
  4. gui_agents/agents/Backend/Backend.py +28 -0
  5. gui_agents/agents/Backend/LybicBackend.py +354 -0
  6. gui_agents/agents/Backend/PyAutoGUIBackend.py +183 -0
  7. gui_agents/agents/Backend/PyAutoGUIVMwareBackend.py +250 -0
  8. gui_agents/agents/Backend/__init__.py +0 -0
  9. gui_agents/agents/agent_s.py +0 -2
  10. gui_agents/agents/grounding.py +1 -6
  11. gui_agents/agents/hardware_interface.py +24 -7
  12. gui_agents/agents/manager.py +0 -3
  13. gui_agents/agents/translator.py +1 -1
  14. gui_agents/agents/worker.py +1 -2
  15. gui_agents/cli_app.py +143 -8
  16. gui_agents/core/engine.py +0 -2
  17. gui_agents/core/knowledge.py +0 -2
  18. gui_agents/lybic_client/__init__.py +0 -0
  19. gui_agents/lybic_client/lybic_client.py +88 -0
  20. gui_agents/prompts/__init__.py +0 -0
  21. gui_agents/prompts/prompts.py +869 -0
  22. gui_agents/service/__init__.py +19 -0
  23. gui_agents/service/agent_service.py +527 -0
  24. gui_agents/service/api_models.py +136 -0
  25. gui_agents/service/config.py +241 -0
  26. gui_agents/service/exceptions.py +35 -0
  27. gui_agents/store/__init__.py +0 -0
  28. gui_agents/store/registry.py +22 -0
  29. gui_agents/tools/tools.py +0 -4
  30. gui_agents/unit_test/test_manager.py +0 -2
  31. gui_agents/unit_test/test_worker.py +0 -2
  32. gui_agents/utils/analyze_display.py +1 -1
  33. gui_agents/utils/common_utils.py +0 -2
  34. {lybic_guiagents-0.1.0.dist-info → lybic_guiagents-0.2.1.dist-info}/METADATA +203 -75
  35. {lybic_guiagents-0.1.0.dist-info → lybic_guiagents-0.2.1.dist-info}/RECORD +38 -21
  36. {lybic_guiagents-0.1.0.dist-info → lybic_guiagents-0.2.1.dist-info}/WHEEL +0 -0
  37. {lybic_guiagents-0.1.0.dist-info → lybic_guiagents-0.2.1.dist-info}/licenses/LICENSE +0 -0
  38. {lybic_guiagents-0.1.0.dist-info → lybic_guiagents-0.2.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,241 @@
1
+ """Configuration management for Agent Service"""
2
+
3
+ import os
4
+ import json
5
+ import platform
6
+ from dataclasses import dataclass, field
7
+ from typing import Dict, Any, Optional, Union
8
+ from pathlib import Path
9
+ from .exceptions import ConfigurationError, APIKeyError
10
+
11
+
12
+ @dataclass
13
+ class LLMConfig:
14
+ """LLM provider configuration"""
15
+ provider: str # openai, anthropic, zhipu, etc.
16
+ model: str
17
+ api_key: Optional[str] = None
18
+ base_url: Optional[str] = None
19
+ api_version: Optional[str] = None
20
+ rate_limit: int = -1
21
+ extra_params: Dict[str, Any] = field(default_factory=dict)
22
+
23
+
24
+ @dataclass
25
+ class ServiceConfig:
26
+ """Comprehensive service configuration with multi-level API key support"""
27
+
28
+ # Agent settings
29
+ default_backend: str = 'lybic'
30
+ default_mode: str = 'normal'
31
+ default_max_steps: int = 50
32
+ default_platform: str = field(default_factory=lambda: platform.system().lower())
33
+
34
+ # Service settings
35
+ max_concurrent_tasks: int = 5
36
+ task_timeout: int = 3600 # 1 hour
37
+ enable_takeover: bool = False
38
+ enable_search: bool = True
39
+
40
+ # Logging settings
41
+ log_level: str = 'INFO'
42
+ log_dir: str = 'runtime'
43
+
44
+ # LLM configuration
45
+ llm_config: Optional[LLMConfig] = None
46
+
47
+ # API Keys - multiple providers support
48
+ api_keys: Dict[str, str] = field(default_factory=dict)
49
+
50
+ # Backend-specific configurations
51
+ backend_configs: Dict[str, Dict[str, Any]] = field(default_factory=dict)
52
+
53
+ # Environment variable mappings
54
+ env_mapping: Dict[str, str] = field(default_factory=lambda: {
55
+ 'AGENT_BACKEND': 'default_backend',
56
+ 'AGENT_MODE': 'default_mode',
57
+ 'AGENT_MAX_STEPS': 'default_max_steps',
58
+ 'AGENT_LOG_LEVEL': 'log_level',
59
+ 'AGENT_LOG_DIR': 'log_dir',
60
+ 'AGENT_TASK_TIMEOUT': 'task_timeout',
61
+ 'AGENT_ENABLE_TAKEOVER': 'enable_takeover',
62
+ 'AGENT_ENABLE_SEARCH': 'enable_search',
63
+ # Lybic specific
64
+ 'LYBIC_PRECREATE_SID': 'lybic_sid',
65
+ 'LYBIC_API_KEY': 'lybic_api_key',
66
+ })
67
+
68
+ # Known API key environment variables
69
+ api_key_env_vars: Dict[str, str] = field(default_factory=lambda: {
70
+ 'openai': 'OPENAI_API_KEY',
71
+ 'anthropic': 'ANTHROPIC_API_KEY',
72
+ 'zhipu': 'ZHIPU_API_KEY',
73
+ 'gemini': 'GEMINI_API_KEY',
74
+ 'groq': 'GROQ_API_KEY',
75
+ 'deepseek': 'DEEPSEEK_API_KEY',
76
+ 'dashscope': 'DASHSCOPE_API_KEY',
77
+ 'azure_openai': 'AZURE_OPENAI_API_KEY',
78
+ 'lybic': 'LYBIC_API_KEY',
79
+ 'huggingface': 'HF_TOKEN',
80
+ 'siliconflow': 'SILICONFLOW_API_KEY',
81
+ 'monica': 'MONICA_API_KEY',
82
+ 'openrouter': 'OPENROUTER_API_KEY',
83
+ })
84
+
85
+ @classmethod
86
+ def from_env(cls, config_file: Optional[Union[str, Path]] = None) -> 'ServiceConfig':
87
+ """Create configuration from environment variables and optional config file
88
+
89
+ Priority order (highest to lowest):
90
+ 1. Environment variables
91
+ 2. Config file
92
+ 3. Default values
93
+ """
94
+ config = cls()
95
+
96
+ # Load from config file first (lower priority)
97
+ if config_file:
98
+ config = config.load_from_file(config_file)
99
+
100
+ # Override with environment variables (higher priority)
101
+ config._load_from_env()
102
+
103
+ return config
104
+
105
+ def _load_from_env(self):
106
+ """Load configuration from environment variables"""
107
+ # Load general settings
108
+ for env_key, attr_name in self.env_mapping.items():
109
+ if env_key in os.environ:
110
+ value = os.environ[env_key]
111
+ # Type conversion based on attribute type
112
+ if hasattr(self, attr_name):
113
+ current_value = getattr(self, attr_name)
114
+ if isinstance(current_value, bool):
115
+ value = value.lower() in ('true', '1', 'yes', 'on')
116
+ elif isinstance(current_value, int):
117
+ try:
118
+ value = int(value)
119
+ except ValueError:
120
+ continue
121
+ setattr(self, attr_name, value)
122
+
123
+ # Load API keys from environment
124
+ for provider, env_var in self.api_key_env_vars.items():
125
+ if env_var in os.environ:
126
+ self.api_keys[provider] = os.environ[env_var]
127
+
128
+ @classmethod
129
+ def load_from_file(cls, config_file: Union[str, Path]) -> 'ServiceConfig':
130
+ """Load configuration from JSON file"""
131
+ config_path = Path(config_file)
132
+
133
+ if not config_path.exists():
134
+ raise ConfigurationError(f"Configuration file not found: {config_path}")
135
+
136
+ try:
137
+ with open(config_path, 'r', encoding='utf-8') as f:
138
+ data = json.load(f)
139
+
140
+ # Create config instance
141
+ config = cls()
142
+
143
+ # Update with file data
144
+ for key, value in data.items():
145
+ if hasattr(config, key):
146
+ setattr(config, key, value)
147
+
148
+ return config
149
+
150
+ except json.JSONDecodeError as e:
151
+ raise ConfigurationError("Invalid JSON in config file") from e
152
+ except OSError as e:
153
+ raise ConfigurationError("Error loading config file") from e
154
+
155
+ def save_to_file(self, config_file: Union[str, Path]):
156
+ """Save configuration to JSON file"""
157
+ config_path = Path(config_file)
158
+ config_path.parent.mkdir(parents=True, exist_ok=True)
159
+
160
+ # Convert to dict, excluding non-serializable fields
161
+ data = {}
162
+ for key, value in self.__dict__.items():
163
+ if not key.startswith('_') and key not in ['env_mapping', 'api_key_env_vars']:
164
+ data[key] = value
165
+
166
+ try:
167
+ with open(config_path, 'w', encoding='utf-8') as f:
168
+ json.dump(data, f, indent=2, ensure_ascii=False)
169
+ except Exception as e:
170
+ raise ConfigurationError(f"Error saving config file: {e}")
171
+
172
+ def get_api_key(self, provider: str, required: bool = True) -> Optional[str]:
173
+ """Get API key for a provider with fallback chain
174
+
175
+ Priority:
176
+ 1. Direct api_keys dict
177
+ 2. Environment variable
178
+ 3. None (if not required)
179
+
180
+ Args:
181
+ provider: Provider name (openai, anthropic, etc.)
182
+ required: Whether to raise error if not found
183
+
184
+ Returns:
185
+ API key string or None
186
+
187
+ Raises:
188
+ APIKeyError: If required but not found
189
+ """
190
+ # Check direct api_keys dict first
191
+ if provider in self.api_keys:
192
+ return self.api_keys[provider]
193
+
194
+ # Check environment variable
195
+ if provider in self.api_key_env_vars:
196
+ env_var = self.api_key_env_vars[provider]
197
+ if env_var in os.environ:
198
+ api_key = os.environ[env_var]
199
+ # Cache it for future use
200
+ self.api_keys[provider] = api_key
201
+ return api_key
202
+
203
+ # Not found
204
+ if required:
205
+ env_var = self.api_key_env_vars.get(provider, f"{provider.upper()}_API_KEY")
206
+ raise APIKeyError(
207
+ f"API key for '{provider}' not found. "
208
+ f"Please provide it via api_keys parameter or {env_var} environment variable"
209
+ )
210
+
211
+ return None
212
+
213
+ def set_api_key(self, provider: str, api_key: str):
214
+ """Set API key for a provider"""
215
+ self.api_keys[provider] = api_key
216
+
217
+ def get_backend_config(self, backend: str) -> Dict[str, Any]:
218
+ """Get backend-specific configuration"""
219
+ return self.backend_configs.get(backend, {})
220
+
221
+ def set_backend_config(self, backend: str, config: Dict[str, Any]):
222
+ """Set backend-specific configuration"""
223
+ self.backend_configs[backend] = config
224
+
225
+ def validate(self):
226
+ """Validate configuration"""
227
+ if self.default_max_steps <= 0:
228
+ raise ConfigurationError("default_max_steps must be positive")
229
+
230
+ if self.task_timeout <= 0:
231
+ raise ConfigurationError("task_timeout must be positive")
232
+
233
+ if self.max_concurrent_tasks <= 0:
234
+ raise ConfigurationError("max_concurrent_tasks must be positive")
235
+
236
+ def to_dict(self) -> Dict[str, Any]:
237
+ """Convert configuration to dictionary"""
238
+ return {
239
+ key: value for key, value in self.__dict__.items()
240
+ if not key.startswith('_')
241
+ }
@@ -0,0 +1,35 @@
1
+ """Custom exceptions for the Agent Service"""
2
+
3
+
4
+ class AgentServiceError(Exception):
5
+ """Base exception for Agent Service errors"""
6
+ pass
7
+
8
+
9
+ class ConfigurationError(AgentServiceError):
10
+ """Raised when there are configuration issues"""
11
+ pass
12
+
13
+
14
+ class TaskExecutionError(AgentServiceError):
15
+ """Raised when task execution fails"""
16
+
17
+ def __init__(self, message: str, task_id: str | None = None, step: int | None = None):
18
+ super().__init__(message)
19
+ self.task_id = task_id
20
+ self.step = step
21
+
22
+
23
+ class TaskTimeoutError(TaskExecutionError):
24
+ """Raised when task execution times out"""
25
+ pass
26
+
27
+
28
+ class BackendError(AgentServiceError):
29
+ """Raised when backend operations fail"""
30
+ pass
31
+
32
+
33
+ class APIKeyError(ConfigurationError):
34
+ """Raised when API key configuration is invalid"""
35
+ pass
File without changes
@@ -0,0 +1,22 @@
1
+ # gui_agents/s2/store/registry.py
2
+
3
+ # Usage: in any file, get the object through Registry.get
4
+ # from gui_agents.store.registry import Registry
5
+ # GlobalStateStore = Registry.get("GlobalStateStore")
6
+
7
+ class Registry:
8
+ _services: dict[str, object] = {}
9
+
10
+ @classmethod
11
+ def register(cls, name: str, obj: object):
12
+ cls._services[name] = obj
13
+
14
+ @classmethod
15
+ def get(cls, name: str) -> object:
16
+ if name not in cls._services:
17
+ raise KeyError(f"{name!r} not registered in Registry")
18
+ return cls._services[name]
19
+
20
+ @classmethod
21
+ def clear(cls):
22
+ cls._services.clear()
gui_agents/tools/tools.py CHANGED
@@ -6,10 +6,6 @@ context fusion, subtask planning, trajectory reflection, memory retrieval, groun
6
6
  evaluation, and action generation.
7
7
  """
8
8
 
9
- import os
10
- import json
11
- import base64
12
- import requests
13
9
  import time
14
10
  from typing import Dict, Any, Optional, List, Union, Tuple
15
11
  from abc import ABC, abstractmethod
@@ -3,9 +3,7 @@ import os
3
3
  import json
4
4
  import logging
5
5
  import sys
6
- from unittest.mock import patch
7
6
  from io import BytesIO
8
- from PIL import Image
9
7
 
10
8
  from gui_agents.agents.manager import Manager
11
9
  from gui_agents.utils.common_utils import Node, Dag
@@ -3,9 +3,7 @@ import os
3
3
  import json
4
4
  import logging
5
5
  import sys
6
- from unittest.mock import MagicMock, patch
7
6
  from io import BytesIO
8
- from PIL import Image
9
7
 
10
8
  from gui_agents.agents.worker import Worker
11
9
  from gui_agents.utils.common_utils import Node
@@ -8,7 +8,7 @@ import json
8
8
  import os
9
9
  import glob
10
10
  import re
11
- from typing import Dict, List, Tuple
11
+ from typing import Dict, List
12
12
 
13
13
 
14
14
  def extract_cost_value(cost_str: str) -> tuple:
@@ -1,7 +1,5 @@
1
1
  import json
2
2
  import re
3
- from typing import List
4
- import time
5
3
  import tiktoken
6
4
  import numpy as np
7
5