agentscope-runtime 1.0.3__py3-none-any.whl → 1.0.4__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.
Files changed (49) hide show
  1. agentscope_runtime/adapters/agentscope/stream.py +2 -9
  2. agentscope_runtime/adapters/ms_agent_framework/__init__.py +0 -0
  3. agentscope_runtime/adapters/ms_agent_framework/message.py +205 -0
  4. agentscope_runtime/adapters/ms_agent_framework/stream.py +418 -0
  5. agentscope_runtime/adapters/utils.py +6 -0
  6. agentscope_runtime/cli/commands/deploy.py +371 -0
  7. agentscope_runtime/common/container_clients/knative_client.py +466 -0
  8. agentscope_runtime/engine/__init__.py +4 -0
  9. agentscope_runtime/engine/constant.py +1 -0
  10. agentscope_runtime/engine/deployers/__init__.py +12 -0
  11. agentscope_runtime/engine/deployers/adapter/a2a/__init__.py +26 -51
  12. agentscope_runtime/engine/deployers/adapter/a2a/a2a_protocol_adapter.py +19 -10
  13. agentscope_runtime/engine/deployers/adapter/a2a/a2a_registry.py +4 -201
  14. agentscope_runtime/engine/deployers/adapter/a2a/nacos_a2a_registry.py +134 -25
  15. agentscope_runtime/engine/deployers/agentrun_deployer.py +2 -2
  16. agentscope_runtime/engine/deployers/fc_deployer.py +1506 -0
  17. agentscope_runtime/engine/deployers/knative_deployer.py +290 -0
  18. agentscope_runtime/engine/runner.py +12 -0
  19. agentscope_runtime/engine/services/agent_state/redis_state_service.py +2 -2
  20. agentscope_runtime/engine/services/memory/redis_memory_service.py +2 -2
  21. agentscope_runtime/engine/services/session_history/redis_session_history_service.py +2 -2
  22. agentscope_runtime/engine/tracing/wrapper.py +18 -4
  23. agentscope_runtime/sandbox/__init__.py +14 -6
  24. agentscope_runtime/sandbox/box/base/__init__.py +2 -2
  25. agentscope_runtime/sandbox/box/base/base_sandbox.py +51 -1
  26. agentscope_runtime/sandbox/box/browser/__init__.py +2 -2
  27. agentscope_runtime/sandbox/box/browser/browser_sandbox.py +198 -2
  28. agentscope_runtime/sandbox/box/filesystem/__init__.py +2 -2
  29. agentscope_runtime/sandbox/box/filesystem/filesystem_sandbox.py +99 -2
  30. agentscope_runtime/sandbox/box/gui/__init__.py +2 -2
  31. agentscope_runtime/sandbox/box/gui/gui_sandbox.py +117 -1
  32. agentscope_runtime/sandbox/box/mobile/__init__.py +2 -2
  33. agentscope_runtime/sandbox/box/mobile/mobile_sandbox.py +247 -100
  34. agentscope_runtime/sandbox/box/sandbox.py +98 -65
  35. agentscope_runtime/sandbox/box/shared/routers/generic.py +36 -29
  36. agentscope_runtime/sandbox/client/__init__.py +6 -1
  37. agentscope_runtime/sandbox/client/async_http_client.py +339 -0
  38. agentscope_runtime/sandbox/client/base.py +74 -0
  39. agentscope_runtime/sandbox/client/http_client.py +108 -329
  40. agentscope_runtime/sandbox/enums.py +7 -0
  41. agentscope_runtime/sandbox/manager/sandbox_manager.py +264 -4
  42. agentscope_runtime/sandbox/manager/server/app.py +7 -1
  43. agentscope_runtime/version.py +1 -1
  44. {agentscope_runtime-1.0.3.dist-info → agentscope_runtime-1.0.4.dist-info}/METADATA +102 -28
  45. {agentscope_runtime-1.0.3.dist-info → agentscope_runtime-1.0.4.dist-info}/RECORD +49 -40
  46. {agentscope_runtime-1.0.3.dist-info → agentscope_runtime-1.0.4.dist-info}/WHEEL +0 -0
  47. {agentscope_runtime-1.0.3.dist-info → agentscope_runtime-1.0.4.dist-info}/entry_points.txt +0 -0
  48. {agentscope_runtime-1.0.3.dist-info → agentscope_runtime-1.0.4.dist-info}/licenses/LICENSE +0 -0
  49. {agentscope_runtime-1.0.3.dist-info → agentscope_runtime-1.0.4.dist-info}/top_level.txt +0 -0
@@ -2,35 +2,20 @@
2
2
  """
3
3
  A2A Registry Extension Point
4
4
 
5
- Defines the abstract interface and helper utilities for A2A registry
6
- implementations. Registry implementations are responsible for registering
7
- agent services to service discovery systems (for example: Nacos).
8
-
9
- This module focuses on clarity and small helper functions used by the
10
- runtime to instantiate registry implementations from environment
11
- configuration or .env files.
5
+ Defines the abstract interface for A2A registry implementations.
6
+ Registry implementations are responsible for registering agent services
7
+ to service discovery systems (for example: Nacos).
12
8
  """
13
9
  import logging
14
- import os
15
10
  from abc import ABC, abstractmethod
16
11
  from dataclasses import dataclass, field
17
- from typing import TYPE_CHECKING, Any, Dict, List, Optional, Union
18
-
19
- from dotenv import find_dotenv, load_dotenv
20
- from pydantic import ConfigDict
21
- from pydantic_settings import BaseSettings
12
+ from typing import Any, Dict, List, Optional
22
13
 
23
14
  from a2a.types import AgentCard
24
15
 
25
- if TYPE_CHECKING:
26
- from v2.nacos import ClientConfig
27
-
28
16
  __all__ = [
29
17
  "A2ARegistry",
30
18
  "A2ATransportsProperties",
31
- "A2ARegistrySettings",
32
- "get_registry_settings",
33
- "create_registry_from_env",
34
19
  ]
35
20
 
36
21
  logger = logging.getLogger(__name__)
@@ -89,185 +74,3 @@ class A2ARegistry(ABC):
89
74
  depending on their semantics.
90
75
  """
91
76
  raise NotImplementedError("Subclasses must implement register()")
92
-
93
-
94
- class A2ARegistrySettings(BaseSettings):
95
- """Settings that control A2A registry behavior.
96
-
97
- Values are loaded from environment variables or a .env file when
98
- `get_registry_settings()` is called.
99
- """
100
-
101
- # Feature toggle
102
- A2A_REGISTRY_ENABLED: bool = True
103
-
104
- # Registry type(s). Can be a single value like "nacos" or a comma-separated
105
- # list of registry types (e.g. "nacos").
106
- A2A_REGISTRY_TYPE: Optional[str] = None
107
-
108
- # Nacos specific configuration
109
- NACOS_SERVER_ADDR: str = "localhost:8848"
110
- NACOS_USERNAME: Optional[str] = None
111
- NACOS_PASSWORD: Optional[str] = None
112
- NACOS_NAMESPACE_ID: Optional[str] = None
113
- NACOS_ACCESS_KEY: Optional[str] = None
114
- NACOS_SECRET_KEY: Optional[str] = None
115
-
116
- model_config = ConfigDict(
117
- extra="allow",
118
- )
119
-
120
-
121
- _registry_settings: Optional[A2ARegistrySettings] = None
122
-
123
-
124
- def get_registry_settings() -> A2ARegistrySettings:
125
- """Return a singleton settings instance, loading .env files if needed."""
126
- global _registry_settings
127
-
128
- if _registry_settings is None:
129
- # Inline _load_env_files() logic
130
- # prefer a .env file if present, otherwise fall back to .env.example
131
- dotenv_path = find_dotenv(raise_error_if_not_found=False)
132
- if dotenv_path:
133
- load_dotenv(dotenv_path, override=False)
134
- else:
135
- # If find_dotenv didn't find a file, try the explicit fallback name
136
- if os.path.exists(".env.example"):
137
- load_dotenv(".env.example", override=False)
138
- _registry_settings = A2ARegistrySettings()
139
-
140
- return _registry_settings
141
-
142
-
143
- def _create_nacos_registry_from_settings(
144
- settings: A2ARegistrySettings,
145
- ) -> Optional[A2ARegistry]:
146
- """Create a NacosRegistry instance from provided settings, or return
147
- None if the required nacos SDK is not available or construction fails."""
148
- try:
149
- # lazy import so package is optional
150
- from .nacos_a2a_registry import NacosRegistry
151
- except ImportError:
152
- logger.warning(
153
- "[A2A] Nacos registry requested but nacos SDK not available. "
154
- "Install with: pip install v2-nacos",
155
- exc_info=False,
156
- )
157
- return None
158
- except Exception as e:
159
- logger.warning(
160
- "[A2A] Unexpected error during Nacos registry import: %s",
161
- str(e),
162
- exc_info=True,
163
- )
164
- return None
165
-
166
- try:
167
- nacos_client_config = _build_nacos_client_config(settings)
168
- registry = NacosRegistry(nacos_client_config=nacos_client_config)
169
-
170
- # Determine authentication status
171
- auth_methods = []
172
- if settings.NACOS_USERNAME and settings.NACOS_PASSWORD:
173
- auth_methods.append("username/password")
174
- if settings.NACOS_ACCESS_KEY and settings.NACOS_SECRET_KEY:
175
- auth_methods.append("access_key")
176
- auth_status = ", ".join(auth_methods) if auth_methods else "disabled"
177
-
178
- namespace_info = (
179
- f", namespace={settings.NACOS_NAMESPACE_ID}"
180
- if settings.NACOS_NAMESPACE_ID
181
- else ""
182
- )
183
- logger.info(
184
- f"[A2A] Created Nacos registry from environment: "
185
- f"server={settings.NACOS_SERVER_ADDR}, "
186
- f"authentication={auth_status}{namespace_info}",
187
- )
188
- return registry
189
- except Exception:
190
- logger.warning(
191
- "[A2A] Failed to construct Nacos registry from settings",
192
- exc_info=True,
193
- )
194
- return None
195
-
196
-
197
- def _build_nacos_client_config(
198
- settings: A2ARegistrySettings,
199
- ) -> Any:
200
- """Build Nacos client configuration from settings.
201
-
202
- Supports both username/password and access key authentication.
203
- """
204
- from v2.nacos import ClientConfigBuilder
205
-
206
- builder = ClientConfigBuilder().server_address(settings.NACOS_SERVER_ADDR)
207
-
208
- if settings.NACOS_NAMESPACE_ID:
209
- builder.namespace_id(settings.NACOS_NAMESPACE_ID)
210
- logger.debug(
211
- "[A2A] Using Nacos namespace: %s",
212
- settings.NACOS_NAMESPACE_ID,
213
- )
214
-
215
- if settings.NACOS_USERNAME and settings.NACOS_PASSWORD:
216
- builder.username(settings.NACOS_USERNAME).password(
217
- settings.NACOS_PASSWORD,
218
- )
219
- logger.debug("[A2A] Using Nacos username/password authentication")
220
-
221
- if settings.NACOS_ACCESS_KEY and settings.NACOS_SECRET_KEY:
222
- builder.access_key(settings.NACOS_ACCESS_KEY).secret_key(
223
- settings.NACOS_SECRET_KEY,
224
- )
225
- logger.debug("[A2A] Using Nacos access key authentication")
226
-
227
- return builder.build()
228
-
229
-
230
- def create_registry_from_env() -> (
231
- Optional[Union[A2ARegistry, List[A2ARegistry]]]
232
- ):
233
- """Create registry instance(s) from environment settings.
234
-
235
- Supports single or multiple registry types (comma-separated).
236
- Returns None if disabled or no valid registry created.
237
- """
238
- settings = get_registry_settings()
239
-
240
- if not settings.A2A_REGISTRY_ENABLED:
241
- logger.debug("[A2A] Registry disabled via A2A_REGISTRY_ENABLED")
242
- return None
243
-
244
- # Inline _split_registry_types() logic
245
- raw = settings.A2A_REGISTRY_TYPE
246
- types = (
247
- [r.strip().lower() for r in raw.split(",") if r.strip()] if raw else []
248
- )
249
- if not types:
250
- logger.debug("[A2A] No registry type specified in A2A_REGISTRY_TYPE")
251
- return None
252
-
253
- registry_list: List[A2ARegistry] = []
254
-
255
- for registry_type in types:
256
- if registry_type == "nacos":
257
- registry = _create_nacos_registry_from_settings(settings)
258
- if registry:
259
- registry_list.append(registry)
260
- else:
261
- logger.debug(
262
- "[A2A] Skipping nacos registry due to earlier errors",
263
- )
264
- else:
265
- logger.warning(
266
- f"[A2A] Unknown registry type requested: "
267
- f"{registry_type}. Supported: nacos",
268
- )
269
-
270
- if not registry_list:
271
- return None
272
-
273
- return registry_list[0] if len(registry_list) == 1 else registry_list
@@ -8,11 +8,17 @@ for A2A protocol adapters.
8
8
  """
9
9
  import asyncio
10
10
  import logging
11
- from enum import Enum
12
- from typing import Optional, TYPE_CHECKING, List
11
+ import os
13
12
  import threading
13
+ from enum import Enum
14
+ from typing import Any, Optional, TYPE_CHECKING, List
14
15
 
15
16
  from a2a.types import AgentCard
17
+ from dotenv import find_dotenv, load_dotenv
18
+ from pydantic import ConfigDict
19
+ from pydantic_settings import BaseSettings
20
+
21
+ logger = logging.getLogger(__name__)
16
22
 
17
23
  # Make the v2.nacos imports optional to avoid hard dependency at
18
24
  # module import time.
@@ -36,6 +42,10 @@ else:
36
42
 
37
43
  _NACOS_SDK_AVAILABLE = True
38
44
  except Exception:
45
+ logger.warning(
46
+ "[NacosRegistry] Nacos SDK (nacos-sdk-python) is not available. "
47
+ "Install it with: pip install nacos-sdk-python",
48
+ )
39
49
 
40
50
  class ClientConfig:
41
51
  pass
@@ -55,12 +65,129 @@ else:
55
65
  _NACOS_SDK_AVAILABLE = False
56
66
 
57
67
  # Import after conditional imports to avoid circular dependencies
68
+ # flake8: noqa: E402
58
69
  from .a2a_registry import ( # pylint: disable=wrong-import-position
59
70
  A2ARegistry,
60
71
  A2ATransportsProperties,
61
72
  )
62
73
 
63
- logger = logging.getLogger(__name__)
74
+
75
+ class NacosSettings(BaseSettings):
76
+ """Nacos-specific settings loaded from environment variables."""
77
+
78
+ NACOS_SERVER_ADDR: str = "localhost:8848"
79
+ NACOS_USERNAME: Optional[str] = None
80
+ NACOS_PASSWORD: Optional[str] = None
81
+ NACOS_NAMESPACE_ID: Optional[str] = None
82
+ NACOS_ACCESS_KEY: Optional[str] = None
83
+ NACOS_SECRET_KEY: Optional[str] = None
84
+
85
+ model_config = ConfigDict(
86
+ extra="allow",
87
+ )
88
+
89
+
90
+ _nacos_settings: Optional[NacosSettings] = None
91
+
92
+
93
+ def get_nacos_settings() -> NacosSettings:
94
+ """Return a singleton Nacos settings instance, loading .env files
95
+ if needed."""
96
+ global _nacos_settings
97
+
98
+ if _nacos_settings is None:
99
+ dotenv_path = find_dotenv(raise_error_if_not_found=False)
100
+ if dotenv_path:
101
+ load_dotenv(dotenv_path, override=False)
102
+ else:
103
+ if os.path.exists(".env.example"):
104
+ load_dotenv(".env.example", override=False)
105
+ _nacos_settings = NacosSettings()
106
+
107
+ return _nacos_settings
108
+
109
+
110
+ def _build_nacos_client_config(settings: NacosSettings) -> Any:
111
+ """Build Nacos client configuration from settings.
112
+
113
+ Supports both username/password and access key authentication.
114
+ """
115
+ try:
116
+ from v2.nacos import ClientConfigBuilder
117
+ except (ImportError, ModuleNotFoundError) as e:
118
+ logger.warning(
119
+ "[A2A] Nacos SDK (nacos-sdk-python) is not available. "
120
+ "Install it with: pip install nacos-sdk-python",
121
+ )
122
+ raise ImportError(
123
+ "Nacos SDK (nacos-sdk-python) is not available. "
124
+ "Install it with: pip install nacos-sdk-python",
125
+ ) from e
126
+
127
+ builder = ClientConfigBuilder().server_address(settings.NACOS_SERVER_ADDR)
128
+
129
+ if settings.NACOS_NAMESPACE_ID:
130
+ builder.namespace_id(settings.NACOS_NAMESPACE_ID)
131
+ logger.debug(
132
+ "[A2A] Using Nacos namespace: %s",
133
+ settings.NACOS_NAMESPACE_ID,
134
+ )
135
+
136
+ if settings.NACOS_USERNAME and settings.NACOS_PASSWORD:
137
+ builder.username(settings.NACOS_USERNAME).password(
138
+ settings.NACOS_PASSWORD,
139
+ )
140
+ logger.debug("[A2A] Using Nacos username/password authentication")
141
+
142
+ if settings.NACOS_ACCESS_KEY and settings.NACOS_SECRET_KEY:
143
+ builder.access_key(settings.NACOS_ACCESS_KEY).secret_key(
144
+ settings.NACOS_SECRET_KEY,
145
+ )
146
+ logger.debug("[A2A] Using Nacos access key authentication")
147
+
148
+ return builder.build()
149
+
150
+
151
+ def create_nacos_registry_from_env() -> Optional[A2ARegistry]:
152
+ """Create a NacosRegistry instance from environment settings.
153
+
154
+ Returns None if the required nacos SDK is not available or
155
+ construction fails.
156
+ """
157
+ if not _NACOS_SDK_AVAILABLE:
158
+ return None
159
+
160
+ try:
161
+ nacos_settings = get_nacos_settings()
162
+ nacos_client_config = _build_nacos_client_config(nacos_settings)
163
+ registry = NacosRegistry(nacos_client_config=nacos_client_config)
164
+
165
+ auth_methods = []
166
+ if nacos_settings.NACOS_USERNAME and nacos_settings.NACOS_PASSWORD:
167
+ auth_methods.append("username/password")
168
+ if nacos_settings.NACOS_ACCESS_KEY and nacos_settings.NACOS_SECRET_KEY:
169
+ auth_methods.append("access_key")
170
+ auth_status = ", ".join(auth_methods) if auth_methods else "disabled"
171
+
172
+ namespace_info = (
173
+ f", namespace={nacos_settings.NACOS_NAMESPACE_ID}"
174
+ if nacos_settings.NACOS_NAMESPACE_ID
175
+ else ""
176
+ )
177
+ logger.info(
178
+ f"[A2A] Created Nacos registry from environment: "
179
+ f"server={nacos_settings.NACOS_SERVER_ADDR}, "
180
+ f"authentication={auth_status}{namespace_info}",
181
+ )
182
+ return registry
183
+ except (ImportError, ModuleNotFoundError):
184
+ return None
185
+ except Exception:
186
+ logger.warning(
187
+ "[A2A] Failed to construct Nacos registry from settings",
188
+ exc_info=True,
189
+ )
190
+ return None
64
191
 
65
192
 
66
193
  class RegistrationStatus(Enum):
@@ -127,11 +254,10 @@ class NacosRegistry(A2ARegistry):
127
254
  a2a_transports_properties: List of transport configurations.
128
255
  Each transport will be registered separately.
129
256
  """
130
- # If Nacos SDK is not available, log and return
131
257
  if not _NACOS_SDK_AVAILABLE:
132
- logger.debug(
133
- "[NacosRegistry] Nacos SDK is not available; "
134
- "skipping registration",
258
+ logger.warning(
259
+ "[NacosRegistry] Nacos SDK (nacos-sdk-python) is not "
260
+ "available. Install it with: pip install nacos-sdk-python",
135
261
  )
136
262
  return
137
263
 
@@ -154,11 +280,7 @@ class NacosRegistry(A2ARegistry):
154
280
  thread and run the registration using asyncio.run so
155
281
  registration still occurs in synchronous contexts.
156
282
  """
157
- # All status checks and updates must be within the lock to
158
- # ensure atomicity
159
283
  with self._registration_lock:
160
- # Check if shutdown was already requested (inside lock
161
- # for atomicity)
162
284
  if self._shutdown_event.is_set():
163
285
  logger.info(
164
286
  "[NacosRegistry] Shutdown already requested, "
@@ -167,7 +289,6 @@ class NacosRegistry(A2ARegistry):
167
289
  self._registration_status = RegistrationStatus.CANCELLED
168
290
  return
169
291
 
170
- # Check if registration is already in progress or completed
171
292
  if self._registration_status in (
172
293
  RegistrationStatus.IN_PROGRESS,
173
294
  RegistrationStatus.COMPLETED,
@@ -184,8 +305,6 @@ class NacosRegistry(A2ARegistry):
184
305
  try:
185
306
  loop = asyncio.get_running_loop()
186
307
  except RuntimeError:
187
- # No running loop in this thread; we'll fall back to a
188
- # background thread
189
308
  loop = None
190
309
 
191
310
  if loop is not None:
@@ -203,7 +322,6 @@ class NacosRegistry(A2ARegistry):
203
322
  )
204
323
  return
205
324
 
206
- # No running loop: use a background thread to run asyncio.run
207
325
  def _thread_runner():
208
326
  try:
209
327
  with self._registration_lock:
@@ -257,8 +375,6 @@ class NacosRegistry(A2ARegistry):
257
375
  daemon=True,
258
376
  )
259
377
  thread.start()
260
- # Store thread reference after successful start for
261
- # proper tracking and cleanup
262
378
  with self._registration_lock:
263
379
  self._register_thread = thread
264
380
  logger.info(
@@ -282,14 +398,7 @@ class NacosRegistry(A2ARegistry):
282
398
  if self._nacos_client_config is not None:
283
399
  return self._nacos_client_config
284
400
 
285
- # Use centralized config builder from a2a_registry module
286
- # This ensures consistent behavior with env-based registry creation
287
- from .a2a_registry import (
288
- get_registry_settings,
289
- _build_nacos_client_config,
290
- )
291
-
292
- settings = get_registry_settings()
401
+ settings = get_nacos_settings()
293
402
  return _build_nacos_client_config(settings)
294
403
 
295
404
  # pylint: disable=too-many-branches,too-many-statements
@@ -7,7 +7,7 @@ import logging
7
7
  import os
8
8
  import time
9
9
  from dataclasses import dataclass
10
- from datetime import datetime
10
+ from datetime import datetime, timedelta
11
11
  from pathlib import Path
12
12
  from typing import Dict, Optional, List, Any, Union, Tuple
13
13
 
@@ -1011,7 +1011,7 @@ ls -lh /output/{zip_filename}
1011
1011
  try:
1012
1012
  presign_result = oss_client.presign(
1013
1013
  GetObjectRequest(bucket=bucket_name, key=object_key),
1014
- expires=datetime.timedelta(hours=3),
1014
+ expires=timedelta(hours=3),
1015
1015
  )
1016
1016
  presigned_url = presign_result.url
1017
1017
  logger.info("Presigned URL generated (valid for 3 hours)")