agentscope-runtime 1.0.4__py3-none-any.whl → 1.0.5__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.
- agentscope_runtime/adapters/agentscope/stream.py +1 -1
- agentscope_runtime/adapters/langgraph/stream.py +120 -70
- agentscope_runtime/cli/commands/deploy.py +465 -1
- agentscope_runtime/cli/commands/stop.py +16 -0
- agentscope_runtime/common/container_clients/__init__.py +52 -0
- agentscope_runtime/common/container_clients/agentrun_client.py +6 -4
- agentscope_runtime/common/container_clients/boxlite_client.py +442 -0
- agentscope_runtime/common/container_clients/docker_client.py +0 -20
- agentscope_runtime/common/container_clients/fc_client.py +6 -4
- agentscope_runtime/common/container_clients/gvisor_client.py +38 -0
- agentscope_runtime/common/container_clients/knative_client.py +1 -0
- agentscope_runtime/common/utils/deprecation.py +164 -0
- agentscope_runtime/engine/app/agent_app.py +16 -4
- agentscope_runtime/engine/deployers/__init__.py +31 -20
- agentscope_runtime/engine/deployers/adapter/__init__.py +8 -0
- agentscope_runtime/engine/deployers/adapter/a2a/a2a_protocol_adapter.py +9 -8
- agentscope_runtime/engine/deployers/adapter/a2a/nacos_a2a_registry.py +19 -1
- agentscope_runtime/engine/deployers/adapter/agui/__init__.py +8 -0
- agentscope_runtime/engine/deployers/adapter/agui/agui_adapter_utils.py +652 -0
- agentscope_runtime/engine/deployers/adapter/agui/agui_protocol_adapter.py +225 -0
- agentscope_runtime/engine/deployers/pai_deployer.py +2335 -0
- agentscope_runtime/engine/deployers/utils/net_utils.py +37 -0
- agentscope_runtime/engine/deployers/utils/oss_utils.py +38 -0
- agentscope_runtime/engine/deployers/utils/package.py +46 -42
- agentscope_runtime/engine/helpers/agent_api_client.py +372 -0
- agentscope_runtime/engine/runner.py +1 -0
- agentscope_runtime/engine/schemas/agent_schemas.py +9 -3
- agentscope_runtime/engine/services/agent_state/__init__.py +7 -0
- agentscope_runtime/engine/services/memory/__init__.py +7 -0
- agentscope_runtime/engine/services/memory/redis_memory_service.py +15 -16
- agentscope_runtime/engine/services/session_history/__init__.py +7 -0
- agentscope_runtime/engine/tracing/local_logging_handler.py +2 -3
- agentscope_runtime/sandbox/box/sandbox.py +4 -0
- agentscope_runtime/sandbox/manager/sandbox_manager.py +11 -25
- agentscope_runtime/sandbox/manager/server/config.py +3 -1
- agentscope_runtime/sandbox/model/manager_config.py +11 -9
- agentscope_runtime/tools/modelstudio_memory/__init__.py +106 -0
- agentscope_runtime/tools/modelstudio_memory/base.py +220 -0
- agentscope_runtime/tools/modelstudio_memory/config.py +86 -0
- agentscope_runtime/tools/modelstudio_memory/core.py +594 -0
- agentscope_runtime/tools/modelstudio_memory/exceptions.py +60 -0
- agentscope_runtime/tools/modelstudio_memory/schemas.py +253 -0
- agentscope_runtime/version.py +1 -1
- {agentscope_runtime-1.0.4.dist-info → agentscope_runtime-1.0.5.dist-info}/METADATA +101 -62
- {agentscope_runtime-1.0.4.dist-info → agentscope_runtime-1.0.5.dist-info}/RECORD +49 -34
- {agentscope_runtime-1.0.4.dist-info → agentscope_runtime-1.0.5.dist-info}/WHEEL +0 -0
- {agentscope_runtime-1.0.4.dist-info → agentscope_runtime-1.0.5.dist-info}/entry_points.txt +0 -0
- {agentscope_runtime-1.0.4.dist-info → agentscope_runtime-1.0.5.dist-info}/licenses/LICENSE +0 -0
- {agentscope_runtime-1.0.4.dist-info → agentscope_runtime-1.0.5.dist-info}/top_level.txt +0 -0
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
2
|
from typing import TYPE_CHECKING
|
|
3
3
|
from ....common.utils.lazy_loader import install_lazy_loader
|
|
4
|
+
from ....common.utils.deprecation import deprecated_module
|
|
5
|
+
|
|
6
|
+
deprecated_module(
|
|
7
|
+
module_name=__name__,
|
|
8
|
+
removed_in="v1.1",
|
|
9
|
+
alternative="agentscope.memory",
|
|
10
|
+
)
|
|
4
11
|
|
|
5
12
|
if TYPE_CHECKING:
|
|
6
13
|
from .session_history_service import (
|
|
@@ -7,7 +7,7 @@ from datetime import datetime
|
|
|
7
7
|
from logging.handlers import RotatingFileHandler
|
|
8
8
|
from typing import Any, Dict, Optional
|
|
9
9
|
|
|
10
|
-
from pydantic import BaseModel
|
|
10
|
+
from pydantic import BaseModel, ConfigDict
|
|
11
11
|
|
|
12
12
|
from . import TracingUtil
|
|
13
13
|
from .base import TracerHandler
|
|
@@ -39,8 +39,7 @@ class LogContext(BaseModel):
|
|
|
39
39
|
ds_service_id: str = ""
|
|
40
40
|
ds_service_name: str = ""
|
|
41
41
|
|
|
42
|
-
|
|
43
|
-
extra = "ignore" # ignore additional key
|
|
42
|
+
model_config = ConfigDict(extra="allow")
|
|
44
43
|
|
|
45
44
|
|
|
46
45
|
class JsonFormatter(logging.Formatter):
|
|
@@ -6,6 +6,7 @@ from typing import Any, Optional
|
|
|
6
6
|
|
|
7
7
|
from ..enums import SandboxType
|
|
8
8
|
from ..manager.sandbox_manager import SandboxManager
|
|
9
|
+
from ..manager.server.app import get_config
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
logging.basicConfig(level=logging.INFO)
|
|
@@ -32,12 +33,15 @@ class SandboxBase:
|
|
|
32
33
|
self._sandbox_id = sandbox_id
|
|
33
34
|
|
|
34
35
|
if base_url:
|
|
36
|
+
# Remote Manager
|
|
35
37
|
self.manager_api = SandboxManager(
|
|
36
38
|
base_url=base_url,
|
|
37
39
|
bearer_token=bearer_token,
|
|
38
40
|
)
|
|
39
41
|
else:
|
|
42
|
+
# Embedded Manager
|
|
40
43
|
self.manager_api = SandboxManager(
|
|
44
|
+
config=get_config(),
|
|
41
45
|
default_type=sandbox_type,
|
|
42
46
|
)
|
|
43
47
|
|
|
@@ -38,6 +38,7 @@ from ...common.collections import (
|
|
|
38
38
|
InMemoryMapping,
|
|
39
39
|
InMemoryQueue,
|
|
40
40
|
)
|
|
41
|
+
from ...common.container_clients import ContainerClientFactory
|
|
41
42
|
from ..constant import TIMEOUT
|
|
42
43
|
|
|
43
44
|
logging.basicConfig(level=logging.INFO)
|
|
@@ -164,7 +165,12 @@ class SandboxManager:
|
|
|
164
165
|
self.httpx_client = None
|
|
165
166
|
self.base_url = None
|
|
166
167
|
|
|
167
|
-
if
|
|
168
|
+
if config:
|
|
169
|
+
logger.debug(
|
|
170
|
+
f"Launching sandbox manager with config:"
|
|
171
|
+
f"\n{config.model_dump()}",
|
|
172
|
+
)
|
|
173
|
+
else:
|
|
168
174
|
config = SandboxManagerEnvConfig(
|
|
169
175
|
file_system="local",
|
|
170
176
|
redis_enabled=False,
|
|
@@ -230,30 +236,10 @@ class SandboxManager:
|
|
|
230
236
|
self.container_deployment = self.config.container_deployment
|
|
231
237
|
|
|
232
238
|
if base_url is None:
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
self.client = DockerClient(config=self.config)
|
|
239
|
-
elif self.container_deployment == "k8s":
|
|
240
|
-
from ...common.container_clients.kubernetes_client import (
|
|
241
|
-
KubernetesClient,
|
|
242
|
-
)
|
|
243
|
-
|
|
244
|
-
self.client = KubernetesClient(config=self.config)
|
|
245
|
-
elif self.container_deployment == "agentrun":
|
|
246
|
-
from ...common.container_clients.agentrun_client import (
|
|
247
|
-
AgentRunClient,
|
|
248
|
-
)
|
|
249
|
-
|
|
250
|
-
self.client = AgentRunClient(config=self.config)
|
|
251
|
-
elif self.container_deployment == "fc":
|
|
252
|
-
from ...common.container_clients.fc_client import FCClient
|
|
253
|
-
|
|
254
|
-
self.client = FCClient(config=self.config)
|
|
255
|
-
else:
|
|
256
|
-
raise NotImplementedError("Not implemented")
|
|
239
|
+
self.client = ContainerClientFactory.create_client(
|
|
240
|
+
deployment_type=self.container_deployment,
|
|
241
|
+
config=self.config,
|
|
242
|
+
)
|
|
257
243
|
else:
|
|
258
244
|
self.client = None
|
|
259
245
|
|
|
@@ -20,7 +20,7 @@ class Settings(BaseSettings):
|
|
|
20
20
|
|
|
21
21
|
# Runtime Manager settings
|
|
22
22
|
DEFAULT_SANDBOX_TYPE: Union[str, List[str]] = "base"
|
|
23
|
-
POOL_SIZE: int =
|
|
23
|
+
POOL_SIZE: int = 0
|
|
24
24
|
AUTO_CLEANUP: bool = True
|
|
25
25
|
CONTAINER_PREFIX_KEY: str = "runtime_sandbox_container_"
|
|
26
26
|
CONTAINER_DEPLOYMENT: Literal[
|
|
@@ -29,6 +29,8 @@ class Settings(BaseSettings):
|
|
|
29
29
|
"k8s",
|
|
30
30
|
"agentrun",
|
|
31
31
|
"fc",
|
|
32
|
+
"gvisor",
|
|
33
|
+
"boxlite",
|
|
32
34
|
] = "docker"
|
|
33
35
|
DEFAULT_MOUNT_DIR: str = "sessions_mount_dir"
|
|
34
36
|
# Read-only mounts (host_path -> container_path)
|
|
@@ -16,15 +16,15 @@ class SandboxManagerEnvConfig(BaseModel):
|
|
|
16
16
|
)
|
|
17
17
|
|
|
18
18
|
file_system: Literal["local", "oss"] = Field(
|
|
19
|
-
|
|
19
|
+
"local",
|
|
20
20
|
description="Type of file system to use: 'local' or 'oss'.",
|
|
21
21
|
)
|
|
22
22
|
storage_folder: Optional[str] = Field(
|
|
23
|
-
"",
|
|
23
|
+
"runtime_sandbox_storage",
|
|
24
24
|
description="Folder path in storage.",
|
|
25
25
|
)
|
|
26
26
|
redis_enabled: bool = Field(
|
|
27
|
-
|
|
27
|
+
False,
|
|
28
28
|
description="Indicates if Redis is enabled.",
|
|
29
29
|
)
|
|
30
30
|
container_deployment: Literal[
|
|
@@ -33,14 +33,16 @@ class SandboxManagerEnvConfig(BaseModel):
|
|
|
33
33
|
"k8s",
|
|
34
34
|
"agentrun",
|
|
35
35
|
"fc",
|
|
36
|
+
"gvisor",
|
|
37
|
+
"boxlite",
|
|
36
38
|
] = Field(
|
|
37
|
-
|
|
39
|
+
"docker",
|
|
38
40
|
description="Container deployment backend: 'docker', 'cloud', 'k8s'"
|
|
39
|
-
" 'agentrun' or '
|
|
41
|
+
" 'agentrun', 'fc', 'knative', or 'gvisor'.",
|
|
40
42
|
)
|
|
41
43
|
|
|
42
44
|
default_mount_dir: Optional[str] = Field(
|
|
43
|
-
|
|
45
|
+
"sessions_mount_dir",
|
|
44
46
|
description="Path for local file system storage.",
|
|
45
47
|
)
|
|
46
48
|
|
|
@@ -67,16 +69,16 @@ class SandboxManagerEnvConfig(BaseModel):
|
|
|
67
69
|
description="OSS endpoint URL. Required if file_system is 'oss'.",
|
|
68
70
|
)
|
|
69
71
|
oss_access_key_id: Optional[str] = Field(
|
|
70
|
-
|
|
72
|
+
"your-access-key-id",
|
|
71
73
|
description="Access key ID for OSS. Required if file_system is 'oss'.",
|
|
72
74
|
)
|
|
73
75
|
oss_access_key_secret: Optional[str] = Field(
|
|
74
|
-
|
|
76
|
+
"your-access-key-secret",
|
|
75
77
|
description="Access key secret for OSS. Required if file_system is "
|
|
76
78
|
"'oss'.",
|
|
77
79
|
)
|
|
78
80
|
oss_bucket_name: Optional[str] = Field(
|
|
79
|
-
|
|
81
|
+
"your-bucket-name",
|
|
80
82
|
description="Bucket name in OSS. Required if file_system is 'oss'.",
|
|
81
83
|
)
|
|
82
84
|
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
ModelStudio Memory Components.
|
|
4
|
+
|
|
5
|
+
This package provides components for interacting with the ModelStudio Memory
|
|
6
|
+
service.
|
|
7
|
+
|
|
8
|
+
Components:
|
|
9
|
+
- AddMemory: Store conversation messages as memory nodes
|
|
10
|
+
- SearchMemory: Search for relevant memories
|
|
11
|
+
- ListMemory: List memory nodes with pagination
|
|
12
|
+
- DeleteMemory: Delete a specific memory node
|
|
13
|
+
- CreateProfileSchema: Create a user profile schema
|
|
14
|
+
- GetUserProfile: Retrieve a user profile
|
|
15
|
+
|
|
16
|
+
Schemas:
|
|
17
|
+
All Pydantic schemas for input/output are available in the schemas
|
|
18
|
+
submodule.
|
|
19
|
+
|
|
20
|
+
Exceptions:
|
|
21
|
+
Custom exceptions for better error handling are available in the
|
|
22
|
+
exceptions submodule.
|
|
23
|
+
|
|
24
|
+
Configuration:
|
|
25
|
+
Configuration can be managed through environment variables or by
|
|
26
|
+
providing a MemoryServiceConfig instance.
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
# Configuration
|
|
30
|
+
from .config import MemoryServiceConfig
|
|
31
|
+
|
|
32
|
+
# Exceptions
|
|
33
|
+
from .exceptions import (
|
|
34
|
+
MemoryAPIError,
|
|
35
|
+
MemoryAuthenticationError,
|
|
36
|
+
MemoryNetworkError,
|
|
37
|
+
MemoryNotFoundError,
|
|
38
|
+
MemoryValidationError,
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
# Components
|
|
42
|
+
from .core import (
|
|
43
|
+
AddMemory,
|
|
44
|
+
SearchMemory,
|
|
45
|
+
ListMemory,
|
|
46
|
+
DeleteMemory,
|
|
47
|
+
CreateProfileSchema,
|
|
48
|
+
GetUserProfile,
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
# Schemas - Import commonly used schemas for convenience
|
|
52
|
+
from .schemas import (
|
|
53
|
+
AddMemoryInput,
|
|
54
|
+
AddMemoryOutput,
|
|
55
|
+
CreateProfileSchemaInput,
|
|
56
|
+
CreateProfileSchemaOutput,
|
|
57
|
+
DeleteMemoryInput,
|
|
58
|
+
DeleteMemoryOutput,
|
|
59
|
+
GetUserProfileInput,
|
|
60
|
+
GetUserProfileOutput,
|
|
61
|
+
ListMemoryInput,
|
|
62
|
+
ListMemoryOutput,
|
|
63
|
+
MemoryNode,
|
|
64
|
+
Message,
|
|
65
|
+
ProfileAttribute,
|
|
66
|
+
SearchMemoryInput,
|
|
67
|
+
SearchMemoryOutput,
|
|
68
|
+
UserProfile,
|
|
69
|
+
UserProfileAttribute,
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
__all__ = [
|
|
73
|
+
# Core Components
|
|
74
|
+
"AddMemory",
|
|
75
|
+
"SearchMemory",
|
|
76
|
+
"ListMemory",
|
|
77
|
+
"DeleteMemory",
|
|
78
|
+
"CreateProfileSchema",
|
|
79
|
+
"GetUserProfile",
|
|
80
|
+
# Configuration
|
|
81
|
+
"MemoryServiceConfig",
|
|
82
|
+
# Exceptions
|
|
83
|
+
"MemoryAPIError",
|
|
84
|
+
"MemoryAuthenticationError",
|
|
85
|
+
"MemoryNetworkError",
|
|
86
|
+
"MemoryNotFoundError",
|
|
87
|
+
"MemoryValidationError",
|
|
88
|
+
# Schemas
|
|
89
|
+
"Message",
|
|
90
|
+
"MemoryNode",
|
|
91
|
+
"AddMemoryInput",
|
|
92
|
+
"AddMemoryOutput",
|
|
93
|
+
"SearchMemoryInput",
|
|
94
|
+
"SearchMemoryOutput",
|
|
95
|
+
"ListMemoryInput",
|
|
96
|
+
"ListMemoryOutput",
|
|
97
|
+
"DeleteMemoryInput",
|
|
98
|
+
"DeleteMemoryOutput",
|
|
99
|
+
"ProfileAttribute",
|
|
100
|
+
"CreateProfileSchemaInput",
|
|
101
|
+
"CreateProfileSchemaOutput",
|
|
102
|
+
"UserProfileAttribute",
|
|
103
|
+
"UserProfile",
|
|
104
|
+
"GetUserProfileInput",
|
|
105
|
+
"GetUserProfileOutput",
|
|
106
|
+
]
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
Base class for ModelStudio Memory components.
|
|
4
|
+
"""
|
|
5
|
+
import logging
|
|
6
|
+
from types import TracebackType
|
|
7
|
+
from typing import Any, Dict, Optional, Type
|
|
8
|
+
|
|
9
|
+
import aiohttp
|
|
10
|
+
|
|
11
|
+
from .config import (
|
|
12
|
+
MemoryServiceConfig,
|
|
13
|
+
)
|
|
14
|
+
from .exceptions import (
|
|
15
|
+
MemoryAPIError,
|
|
16
|
+
MemoryAuthenticationError,
|
|
17
|
+
MemoryNetworkError,
|
|
18
|
+
MemoryNotFoundError,
|
|
19
|
+
MemoryValidationError,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
logger = logging.getLogger(__name__)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class ModelStudioMemoryBase:
|
|
26
|
+
"""
|
|
27
|
+
Base class for ModelStudio Memory API components.
|
|
28
|
+
|
|
29
|
+
This class provides common functionality for all memory components,
|
|
30
|
+
including:
|
|
31
|
+
- Configuration management
|
|
32
|
+
- HTTP request handling with error handling
|
|
33
|
+
- Common headers generation
|
|
34
|
+
- Session management
|
|
35
|
+
|
|
36
|
+
Attributes:
|
|
37
|
+
config: Configuration for the memory service
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
def __init__(self, config: Optional[MemoryServiceConfig] = None):
|
|
41
|
+
"""
|
|
42
|
+
Initialize the base memory component.
|
|
43
|
+
|
|
44
|
+
Args:
|
|
45
|
+
config: Optional configuration. If not provided, will be loaded
|
|
46
|
+
from environment variables.
|
|
47
|
+
|
|
48
|
+
Raises:
|
|
49
|
+
ValueError: If required configuration is missing
|
|
50
|
+
"""
|
|
51
|
+
self.config = config or MemoryServiceConfig.from_env()
|
|
52
|
+
self._session: Optional[aiohttp.ClientSession] = None
|
|
53
|
+
|
|
54
|
+
def _get_headers(self) -> Dict[str, str]:
|
|
55
|
+
"""
|
|
56
|
+
Get common HTTP headers for API requests.
|
|
57
|
+
|
|
58
|
+
Returns:
|
|
59
|
+
Dictionary of HTTP headers
|
|
60
|
+
"""
|
|
61
|
+
return {
|
|
62
|
+
"Content-Type": "application/json",
|
|
63
|
+
"User-Agent": "agentscope-runtime",
|
|
64
|
+
"Authorization": f"Bearer {self.config.api_key}",
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async def _get_session(self) -> aiohttp.ClientSession:
|
|
68
|
+
"""
|
|
69
|
+
Get or create an aiohttp session.
|
|
70
|
+
|
|
71
|
+
Returns:
|
|
72
|
+
An aiohttp ClientSession
|
|
73
|
+
"""
|
|
74
|
+
if self._session is None or self._session.closed:
|
|
75
|
+
self._session = aiohttp.ClientSession()
|
|
76
|
+
return self._session
|
|
77
|
+
|
|
78
|
+
async def _request(
|
|
79
|
+
self,
|
|
80
|
+
method: str,
|
|
81
|
+
url: str,
|
|
82
|
+
**kwargs: Any,
|
|
83
|
+
) -> Dict[str, Any]:
|
|
84
|
+
"""
|
|
85
|
+
Common HTTP request handler with comprehensive error handling.
|
|
86
|
+
|
|
87
|
+
Args:
|
|
88
|
+
method: HTTP method (GET, POST, DELETE, etc.)
|
|
89
|
+
url: Request URL
|
|
90
|
+
**kwargs: Additional arguments for the request
|
|
91
|
+
|
|
92
|
+
Returns:
|
|
93
|
+
Response JSON as dictionary
|
|
94
|
+
|
|
95
|
+
Raises:
|
|
96
|
+
MemoryAuthenticationError: If authentication fails (401)
|
|
97
|
+
MemoryNotFoundError: If resource not found (404)
|
|
98
|
+
MemoryAPIError: For other API errors
|
|
99
|
+
MemoryNetworkError: For network-related errors
|
|
100
|
+
"""
|
|
101
|
+
try:
|
|
102
|
+
session = await self._get_session()
|
|
103
|
+
logger.debug(f"Making {method} request to {url}")
|
|
104
|
+
|
|
105
|
+
async with session.request(
|
|
106
|
+
method,
|
|
107
|
+
url,
|
|
108
|
+
headers=self._get_headers(),
|
|
109
|
+
**kwargs,
|
|
110
|
+
) as response:
|
|
111
|
+
# Handle successful response
|
|
112
|
+
if response.status == 200:
|
|
113
|
+
result = await response.json()
|
|
114
|
+
logger.debug(
|
|
115
|
+
f"Request successful: {method} {url}",
|
|
116
|
+
)
|
|
117
|
+
return result
|
|
118
|
+
|
|
119
|
+
# Handle error responses (4XX, 5XX)
|
|
120
|
+
# Try to parse JSON error response first
|
|
121
|
+
error_data = None
|
|
122
|
+
try:
|
|
123
|
+
error_data = await response.json()
|
|
124
|
+
except Exception:
|
|
125
|
+
# If JSON parsing fails, fall back to text
|
|
126
|
+
error_text = await response.text()
|
|
127
|
+
error_data = {"message": error_text}
|
|
128
|
+
|
|
129
|
+
# Extract error information
|
|
130
|
+
error_code = error_data.get("code", "Unknown")
|
|
131
|
+
error_message = error_data.get("message", "Unknown error")
|
|
132
|
+
request_id = error_data.get("request_id", "")
|
|
133
|
+
|
|
134
|
+
# Format error log
|
|
135
|
+
error_log = (
|
|
136
|
+
f"API Error - Status: {response.status}, "
|
|
137
|
+
f"Code: {error_code}, Message: {error_message}, "
|
|
138
|
+
f"Request ID: {request_id}"
|
|
139
|
+
)
|
|
140
|
+
logger.error(error_log)
|
|
141
|
+
|
|
142
|
+
# Raise appropriate exception based on status code
|
|
143
|
+
if response.status in [401, 403]:
|
|
144
|
+
raise MemoryAuthenticationError(
|
|
145
|
+
error_message,
|
|
146
|
+
status_code=response.status,
|
|
147
|
+
error_code=error_code,
|
|
148
|
+
request_id=request_id,
|
|
149
|
+
)
|
|
150
|
+
if response.status == 404:
|
|
151
|
+
raise MemoryNotFoundError(
|
|
152
|
+
error_message,
|
|
153
|
+
status_code=response.status,
|
|
154
|
+
error_code=error_code,
|
|
155
|
+
request_id=request_id,
|
|
156
|
+
)
|
|
157
|
+
if response.status == 400:
|
|
158
|
+
raise MemoryValidationError(
|
|
159
|
+
error_message,
|
|
160
|
+
status_code=response.status,
|
|
161
|
+
error_code=error_code,
|
|
162
|
+
request_id=request_id,
|
|
163
|
+
)
|
|
164
|
+
if 400 <= response.status < 500:
|
|
165
|
+
# Other 4XX errors
|
|
166
|
+
raise MemoryValidationError(
|
|
167
|
+
error_message,
|
|
168
|
+
status_code=response.status,
|
|
169
|
+
error_code=error_code,
|
|
170
|
+
request_id=request_id,
|
|
171
|
+
)
|
|
172
|
+
raise MemoryAPIError(
|
|
173
|
+
error_message,
|
|
174
|
+
status_code=response.status,
|
|
175
|
+
error_code=error_code,
|
|
176
|
+
request_id=request_id,
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
except aiohttp.ClientError as e:
|
|
180
|
+
logger.exception(f"Network error: {str(e)}")
|
|
181
|
+
raise MemoryNetworkError(
|
|
182
|
+
f"Network error during {method} request to {url}: {str(e)}",
|
|
183
|
+
) from e
|
|
184
|
+
except (
|
|
185
|
+
MemoryAuthenticationError,
|
|
186
|
+
MemoryNotFoundError,
|
|
187
|
+
MemoryValidationError,
|
|
188
|
+
MemoryAPIError,
|
|
189
|
+
):
|
|
190
|
+
# Re-raise our custom exceptions (already have proper error info)
|
|
191
|
+
raise
|
|
192
|
+
except Exception as e:
|
|
193
|
+
logger.exception(f"Unexpected error: {str(e)}")
|
|
194
|
+
raise MemoryAPIError(
|
|
195
|
+
f"Unexpected error during {method} request to {url}: {str(e)}",
|
|
196
|
+
) from e
|
|
197
|
+
|
|
198
|
+
async def close(self) -> None:
|
|
199
|
+
"""
|
|
200
|
+
Close the HTTP session.
|
|
201
|
+
|
|
202
|
+
Should be called when the component is no longer needed to clean up
|
|
203
|
+
resources.
|
|
204
|
+
"""
|
|
205
|
+
if self._session and not self._session.closed:
|
|
206
|
+
await self._session.close()
|
|
207
|
+
logger.debug("Session closed")
|
|
208
|
+
|
|
209
|
+
async def __aenter__(self) -> "ModelStudioMemoryBase":
|
|
210
|
+
"""Support async context manager."""
|
|
211
|
+
return self
|
|
212
|
+
|
|
213
|
+
async def __aexit__(
|
|
214
|
+
self,
|
|
215
|
+
exc_type: Optional[Type[BaseException]],
|
|
216
|
+
exc_val: Optional[BaseException],
|
|
217
|
+
exc_tb: Optional[TracebackType],
|
|
218
|
+
) -> None:
|
|
219
|
+
"""Support async context manager."""
|
|
220
|
+
await self.close()
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
Configuration management for ModelStudio Memory service.
|
|
4
|
+
"""
|
|
5
|
+
import os
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
# Default endpoint
|
|
10
|
+
DEFAULT_MEMORY_SERVICE_ENDPOINT = (
|
|
11
|
+
"https://dashscope.aliyuncs.com/api/v2/apps/memory"
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@dataclass
|
|
16
|
+
class MemoryServiceConfig:
|
|
17
|
+
"""
|
|
18
|
+
Configuration for ModelStudio Memory Service.
|
|
19
|
+
|
|
20
|
+
Attributes:
|
|
21
|
+
api_key: DashScope API key for authentication
|
|
22
|
+
service_endpoint: Base URL for the memory service API
|
|
23
|
+
service_id: Service identifier
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
api_key: str
|
|
27
|
+
service_endpoint: str = DEFAULT_MEMORY_SERVICE_ENDPOINT
|
|
28
|
+
service_id: str = "memory_service"
|
|
29
|
+
|
|
30
|
+
@classmethod
|
|
31
|
+
def from_env(cls) -> "MemoryServiceConfig":
|
|
32
|
+
"""
|
|
33
|
+
Create configuration from environment variables.
|
|
34
|
+
|
|
35
|
+
Environment Variables:
|
|
36
|
+
DASHSCOPE_API_KEY: Required. API key for authentication
|
|
37
|
+
MEMORY_SERVICE_ENDPOINT: Optional. API endpoint URL
|
|
38
|
+
MODELSTUDIO_SERVICE_ID: Optional. Service identifier
|
|
39
|
+
|
|
40
|
+
Returns:
|
|
41
|
+
MemoryServiceConfig: Configuration instance
|
|
42
|
+
|
|
43
|
+
Raises:
|
|
44
|
+
ValueError: If DASHSCOPE_API_KEY is not set
|
|
45
|
+
"""
|
|
46
|
+
api_key = os.getenv("DASHSCOPE_API_KEY")
|
|
47
|
+
if not api_key:
|
|
48
|
+
raise ValueError(
|
|
49
|
+
"DASHSCOPE_API_KEY environment variable is required. "
|
|
50
|
+
"Please set it before using ModelStudio Memory components.",
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
return cls(
|
|
54
|
+
api_key=api_key,
|
|
55
|
+
service_endpoint=os.getenv(
|
|
56
|
+
"MEMORY_SERVICE_ENDPOINT",
|
|
57
|
+
DEFAULT_MEMORY_SERVICE_ENDPOINT,
|
|
58
|
+
),
|
|
59
|
+
service_id=os.getenv("MODELSTUDIO_SERVICE_ID", "memory_service"),
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
def get_add_memory_url(self) -> str:
|
|
63
|
+
"""Get URL for adding memory."""
|
|
64
|
+
return f"{self.service_endpoint}/add"
|
|
65
|
+
|
|
66
|
+
def get_search_memory_url(self) -> str:
|
|
67
|
+
"""Get URL for searching memory."""
|
|
68
|
+
return f"{self.service_endpoint}/memory_nodes/search"
|
|
69
|
+
|
|
70
|
+
def get_list_memory_url(self) -> str:
|
|
71
|
+
"""Get URL for listing memory."""
|
|
72
|
+
return f"{self.service_endpoint}/memory_nodes"
|
|
73
|
+
|
|
74
|
+
def get_delete_memory_url(self, memory_node_id: str) -> str:
|
|
75
|
+
"""Get URL for deleting a specific memory node."""
|
|
76
|
+
return f"{self.service_endpoint}/memory_nodes/{memory_node_id}"
|
|
77
|
+
|
|
78
|
+
def get_create_profile_schema_url(self) -> str:
|
|
79
|
+
"""Get URL for creating profile schema."""
|
|
80
|
+
return f"{self.service_endpoint}/profile_schemas"
|
|
81
|
+
|
|
82
|
+
def get_user_profile_url(self, schema_id: str) -> str:
|
|
83
|
+
"""Get URL for getting user profile."""
|
|
84
|
+
return (
|
|
85
|
+
f"{self.service_endpoint}/profile_schemas/{schema_id}/user_profile"
|
|
86
|
+
)
|