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
|
@@ -0,0 +1,594 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
ModelStudio Memory Components.
|
|
4
|
+
|
|
5
|
+
This module provides components for interacting with the ModelStudio Memory
|
|
6
|
+
service, enabling:
|
|
7
|
+
- Adding conversation memories
|
|
8
|
+
- Searching for relevant memories
|
|
9
|
+
- Listing and managing memory nodes
|
|
10
|
+
- Creating and retrieving user profiles
|
|
11
|
+
|
|
12
|
+
All components support async operations and follow the Component pattern.
|
|
13
|
+
"""
|
|
14
|
+
import logging
|
|
15
|
+
from typing import Any, Optional
|
|
16
|
+
|
|
17
|
+
from ..base import Tool
|
|
18
|
+
from .base import ModelStudioMemoryBase
|
|
19
|
+
from .config import MemoryServiceConfig
|
|
20
|
+
from .schemas import (
|
|
21
|
+
AddMemoryInput,
|
|
22
|
+
AddMemoryOutput,
|
|
23
|
+
CreateProfileSchemaInput,
|
|
24
|
+
CreateProfileSchemaOutput,
|
|
25
|
+
DeleteMemoryInput,
|
|
26
|
+
DeleteMemoryOutput,
|
|
27
|
+
GetUserProfileInput,
|
|
28
|
+
GetUserProfileOutput,
|
|
29
|
+
ListMemoryInput,
|
|
30
|
+
ListMemoryOutput,
|
|
31
|
+
MemoryNode,
|
|
32
|
+
SearchMemoryInput,
|
|
33
|
+
SearchMemoryOutput,
|
|
34
|
+
UserProfile,
|
|
35
|
+
UserProfileAttribute,
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
logger = logging.getLogger(__name__)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class AddMemory(
|
|
42
|
+
Tool[AddMemoryInput, AddMemoryOutput],
|
|
43
|
+
ModelStudioMemoryBase,
|
|
44
|
+
):
|
|
45
|
+
"""
|
|
46
|
+
Component for storing conversation history as memory nodes.
|
|
47
|
+
|
|
48
|
+
This component sends conversation messages to the ModelStudio Memory
|
|
49
|
+
to be processed and stored as searchable memory nodes. The service
|
|
50
|
+
automatically extracts and structures relevant information.
|
|
51
|
+
|
|
52
|
+
Environment Variables:
|
|
53
|
+
DASHSCOPE_API_KEY: Required. API key for authentication
|
|
54
|
+
MODELSTUDIO_SERVICE_ID: Optional. Service identifier
|
|
55
|
+
(default: "memory_service")
|
|
56
|
+
MEMORY_SERVICE_ENDPOINT: Optional. API endpoint URL
|
|
57
|
+
(default: https://dashscope.aliyuncs.com/api/v2/apps/memory)
|
|
58
|
+
|
|
59
|
+
Raises:
|
|
60
|
+
ValueError: If DASHSCOPE_API_KEY is not set
|
|
61
|
+
MemoryAPIError: If the API request fails
|
|
62
|
+
MemoryAuthenticationError: If authentication fails
|
|
63
|
+
MemoryNetworkError: If network communication fails
|
|
64
|
+
"""
|
|
65
|
+
|
|
66
|
+
name = "add_memory"
|
|
67
|
+
description = "Store conversation messages as memory nodes"
|
|
68
|
+
|
|
69
|
+
def __init__(self, config: Optional[MemoryServiceConfig] = None) -> None:
|
|
70
|
+
"""
|
|
71
|
+
Initialize the AddMemory component.
|
|
72
|
+
|
|
73
|
+
Args:
|
|
74
|
+
config: Optional configuration. If not provided, will be loaded
|
|
75
|
+
from environment variables.
|
|
76
|
+
"""
|
|
77
|
+
Tool.__init__(self)
|
|
78
|
+
ModelStudioMemoryBase.__init__(self, config)
|
|
79
|
+
|
|
80
|
+
async def _arun(
|
|
81
|
+
self,
|
|
82
|
+
args: AddMemoryInput,
|
|
83
|
+
**kwargs: Any,
|
|
84
|
+
) -> AddMemoryOutput:
|
|
85
|
+
"""
|
|
86
|
+
Add memory nodes for the given conversation.
|
|
87
|
+
|
|
88
|
+
Args:
|
|
89
|
+
args: Input containing user_id, messages, timestamp, and optional
|
|
90
|
+
metadata
|
|
91
|
+
**kwargs: Additional parameters (currently unused)
|
|
92
|
+
|
|
93
|
+
Returns:
|
|
94
|
+
AddMemoryOutput containing the created memory nodes and request_id
|
|
95
|
+
|
|
96
|
+
Raises:
|
|
97
|
+
MemoryAPIError: If the API request fails
|
|
98
|
+
"""
|
|
99
|
+
logger.info(f"Adding memory for user {args.user_id}")
|
|
100
|
+
|
|
101
|
+
try:
|
|
102
|
+
# Build request payload
|
|
103
|
+
payload = args.model_dump(exclude_none=True)
|
|
104
|
+
|
|
105
|
+
# Send request
|
|
106
|
+
result = await self._request(
|
|
107
|
+
"POST",
|
|
108
|
+
self.config.get_add_memory_url(),
|
|
109
|
+
json=payload,
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
# Debug: print API response structure
|
|
113
|
+
logger.debug(f"API Response: {result}")
|
|
114
|
+
logger.debug(
|
|
115
|
+
f"memory_nodes type: {type(result.get('memory_nodes'))}",
|
|
116
|
+
)
|
|
117
|
+
logger.debug(f"memory_nodes value: {result.get('memory_nodes')}")
|
|
118
|
+
|
|
119
|
+
# Parse response - handle both list and dict formats
|
|
120
|
+
memory_nodes_raw = result.get("memory_nodes", [])
|
|
121
|
+
if isinstance(memory_nodes_raw, dict):
|
|
122
|
+
# If it's a dict (single node), wrap it in a list
|
|
123
|
+
memory_nodes_list = [memory_nodes_raw]
|
|
124
|
+
elif isinstance(memory_nodes_raw, list):
|
|
125
|
+
memory_nodes_list = memory_nodes_raw
|
|
126
|
+
else:
|
|
127
|
+
memory_nodes_list = []
|
|
128
|
+
|
|
129
|
+
output = AddMemoryOutput(
|
|
130
|
+
memory_nodes=[
|
|
131
|
+
MemoryNode(**node) for node in memory_nodes_list
|
|
132
|
+
],
|
|
133
|
+
request_id=result.get("request_id", ""),
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
logger.info(
|
|
137
|
+
f"Successfully added {len(output.memory_nodes)} memory nodes",
|
|
138
|
+
)
|
|
139
|
+
return output
|
|
140
|
+
|
|
141
|
+
except Exception:
|
|
142
|
+
logger.exception(f"Failed to add memory for user {args.user_id}")
|
|
143
|
+
raise
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
class SearchMemory(
|
|
147
|
+
Tool[SearchMemoryInput, SearchMemoryOutput],
|
|
148
|
+
ModelStudioMemoryBase,
|
|
149
|
+
):
|
|
150
|
+
"""
|
|
151
|
+
Component for searching relevant memories based on conversation context.
|
|
152
|
+
|
|
153
|
+
This component searches the memory database for relevant past conversations
|
|
154
|
+
and information based on the current conversation context.
|
|
155
|
+
|
|
156
|
+
Environment Variables:
|
|
157
|
+
DASHSCOPE_API_KEY: Required. API key for authentication
|
|
158
|
+
MODELSTUDIO_SERVICE_ID: Optional. Service identifier
|
|
159
|
+
MEMORY_SERVICE_ENDPOINT: Optional. API endpoint URL
|
|
160
|
+
|
|
161
|
+
Raises:
|
|
162
|
+
ValueError: If DASHSCOPE_API_KEY is not set
|
|
163
|
+
MemoryAPIError: If the API request fails
|
|
164
|
+
"""
|
|
165
|
+
|
|
166
|
+
name = "search_memory"
|
|
167
|
+
description = "Search for relevant memories based on conversation context"
|
|
168
|
+
|
|
169
|
+
def __init__(self, config: Optional[MemoryServiceConfig] = None) -> None:
|
|
170
|
+
"""
|
|
171
|
+
Initialize the SearchMemory component.
|
|
172
|
+
|
|
173
|
+
Args:
|
|
174
|
+
config: Optional configuration. If not provided, will be loaded
|
|
175
|
+
from environment variables.
|
|
176
|
+
"""
|
|
177
|
+
Tool.__init__(self)
|
|
178
|
+
ModelStudioMemoryBase.__init__(self, config)
|
|
179
|
+
|
|
180
|
+
async def _arun(
|
|
181
|
+
self,
|
|
182
|
+
args: SearchMemoryInput,
|
|
183
|
+
**kwargs: Any,
|
|
184
|
+
) -> SearchMemoryOutput:
|
|
185
|
+
"""
|
|
186
|
+
Search for relevant memory nodes.
|
|
187
|
+
|
|
188
|
+
Args:
|
|
189
|
+
args: Input containing user_id, messages, top_k, and min_score
|
|
190
|
+
**kwargs: Additional parameters (currently unused)
|
|
191
|
+
|
|
192
|
+
Returns:
|
|
193
|
+
SearchMemoryOutput containing retrieved memory nodes and request_id
|
|
194
|
+
|
|
195
|
+
Raises:
|
|
196
|
+
MemoryAPIError: If the API request fails
|
|
197
|
+
"""
|
|
198
|
+
logger.info(
|
|
199
|
+
f"Searching memory for user {args.user_id} "
|
|
200
|
+
f"(top_k={args.top_k}, min_score={args.min_score})",
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
try:
|
|
204
|
+
# Build request payload
|
|
205
|
+
payload = args.model_dump(exclude_none=True)
|
|
206
|
+
|
|
207
|
+
# Send request
|
|
208
|
+
result = await self._request(
|
|
209
|
+
"POST",
|
|
210
|
+
self.config.get_search_memory_url(),
|
|
211
|
+
json=payload,
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
# Parse response
|
|
215
|
+
output = SearchMemoryOutput(
|
|
216
|
+
memory_nodes=[
|
|
217
|
+
MemoryNode(**node)
|
|
218
|
+
for node in result.get("memory_nodes", [])
|
|
219
|
+
],
|
|
220
|
+
request_id=result.get("request_id", ""),
|
|
221
|
+
)
|
|
222
|
+
|
|
223
|
+
logger.info(
|
|
224
|
+
f"Found {len(output.memory_nodes)} memory nodes for "
|
|
225
|
+
f"user {args.user_id}",
|
|
226
|
+
)
|
|
227
|
+
return output
|
|
228
|
+
|
|
229
|
+
except Exception:
|
|
230
|
+
logger.exception(
|
|
231
|
+
f"Failed to search memory for user {args.user_id}",
|
|
232
|
+
)
|
|
233
|
+
raise
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
class ListMemory(
|
|
237
|
+
Tool[ListMemoryInput, ListMemoryOutput],
|
|
238
|
+
ModelStudioMemoryBase,
|
|
239
|
+
):
|
|
240
|
+
"""
|
|
241
|
+
Component for listing memory nodes with pagination.
|
|
242
|
+
|
|
243
|
+
This component retrieves a paginated list of all memory nodes for a
|
|
244
|
+
specific user.
|
|
245
|
+
|
|
246
|
+
Environment Variables:
|
|
247
|
+
DASHSCOPE_API_KEY: Required. API key for authentication
|
|
248
|
+
MODELSTUDIO_SERVICE_ID: Optional. Service identifier
|
|
249
|
+
MEMORY_SERVICE_ENDPOINT: Optional. API endpoint URL
|
|
250
|
+
|
|
251
|
+
Raises:
|
|
252
|
+
ValueError: If DASHSCOPE_API_KEY is not set
|
|
253
|
+
MemoryAPIError: If the API request fails
|
|
254
|
+
"""
|
|
255
|
+
|
|
256
|
+
name = "list_memory"
|
|
257
|
+
description = "List memory nodes for a user with pagination"
|
|
258
|
+
|
|
259
|
+
def __init__(self, config: Optional[MemoryServiceConfig] = None) -> None:
|
|
260
|
+
"""
|
|
261
|
+
Initialize the ListMemory component.
|
|
262
|
+
|
|
263
|
+
Args:
|
|
264
|
+
config: Optional configuration. If not provided, will be loaded
|
|
265
|
+
from environment variables.
|
|
266
|
+
"""
|
|
267
|
+
Tool.__init__(self)
|
|
268
|
+
ModelStudioMemoryBase.__init__(self, config)
|
|
269
|
+
|
|
270
|
+
async def _arun(
|
|
271
|
+
self,
|
|
272
|
+
args: ListMemoryInput,
|
|
273
|
+
**kwargs: Any,
|
|
274
|
+
) -> ListMemoryOutput:
|
|
275
|
+
"""
|
|
276
|
+
List memory nodes for a user with pagination.
|
|
277
|
+
|
|
278
|
+
Args:
|
|
279
|
+
args: Input containing user_id, page_num, and page_size
|
|
280
|
+
**kwargs: Additional parameters (currently unused)
|
|
281
|
+
|
|
282
|
+
Returns:
|
|
283
|
+
ListMemoryOutput containing memory nodes, pagination info,
|
|
284
|
+
and request_id
|
|
285
|
+
|
|
286
|
+
Raises:
|
|
287
|
+
MemoryAPIError: If the API request fails
|
|
288
|
+
"""
|
|
289
|
+
logger.info(
|
|
290
|
+
f"Listing memory for user {args.user_id} "
|
|
291
|
+
f"(page {args.page_num}, size {args.page_size})",
|
|
292
|
+
)
|
|
293
|
+
|
|
294
|
+
try:
|
|
295
|
+
# Build request params
|
|
296
|
+
params = args.model_dump(exclude_none=True)
|
|
297
|
+
|
|
298
|
+
# Send request (GET with query parameters)
|
|
299
|
+
result = await self._request(
|
|
300
|
+
"GET",
|
|
301
|
+
self.config.get_list_memory_url(),
|
|
302
|
+
params=params,
|
|
303
|
+
)
|
|
304
|
+
|
|
305
|
+
# Parse response
|
|
306
|
+
output = ListMemoryOutput(
|
|
307
|
+
memory_nodes=[
|
|
308
|
+
MemoryNode(**node)
|
|
309
|
+
for node in result.get("memory_nodes", [])
|
|
310
|
+
],
|
|
311
|
+
page_size=result.get("page_size", args.page_size or 10),
|
|
312
|
+
page_num=result.get("page_num", args.page_num or 1),
|
|
313
|
+
total=result.get("total", 0),
|
|
314
|
+
request_id=result.get("request_id", ""),
|
|
315
|
+
)
|
|
316
|
+
|
|
317
|
+
logger.info(
|
|
318
|
+
f"Retrieved {len(output.memory_nodes)} memory nodes "
|
|
319
|
+
f"(total: {output.total})",
|
|
320
|
+
)
|
|
321
|
+
return output
|
|
322
|
+
|
|
323
|
+
except Exception:
|
|
324
|
+
logger.exception(f"Failed to list memory for user {args.user_id}")
|
|
325
|
+
raise
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
class DeleteMemory(
|
|
329
|
+
Tool[DeleteMemoryInput, DeleteMemoryOutput],
|
|
330
|
+
ModelStudioMemoryBase,
|
|
331
|
+
):
|
|
332
|
+
"""
|
|
333
|
+
Component for deleting a specific memory node.
|
|
334
|
+
|
|
335
|
+
This component deletes a memory node by its ID.
|
|
336
|
+
|
|
337
|
+
Environment Variables:
|
|
338
|
+
DASHSCOPE_API_KEY: Required. API key for authentication
|
|
339
|
+
MODELSTUDIO_SERVICE_ID: Optional. Service identifier
|
|
340
|
+
MEMORY_SERVICE_ENDPOINT: Optional. API endpoint URL
|
|
341
|
+
|
|
342
|
+
Raises:
|
|
343
|
+
ValueError: If DASHSCOPE_API_KEY is not set
|
|
344
|
+
MemoryAPIError: If the API request fails
|
|
345
|
+
MemoryNotFoundError: If the memory node is not found
|
|
346
|
+
"""
|
|
347
|
+
|
|
348
|
+
name = "delete_memory"
|
|
349
|
+
description = "Delete a specific memory node"
|
|
350
|
+
|
|
351
|
+
def __init__(self, config: Optional[MemoryServiceConfig] = None) -> None:
|
|
352
|
+
"""
|
|
353
|
+
Initialize the DeleteMemory component.
|
|
354
|
+
|
|
355
|
+
Args:
|
|
356
|
+
config: Optional configuration. If not provided, will be loaded
|
|
357
|
+
from environment variables.
|
|
358
|
+
"""
|
|
359
|
+
Tool.__init__(self)
|
|
360
|
+
ModelStudioMemoryBase.__init__(self, config)
|
|
361
|
+
|
|
362
|
+
async def _arun(
|
|
363
|
+
self,
|
|
364
|
+
args: DeleteMemoryInput,
|
|
365
|
+
**kwargs: Any,
|
|
366
|
+
) -> DeleteMemoryOutput:
|
|
367
|
+
"""
|
|
368
|
+
Delete a memory node.
|
|
369
|
+
|
|
370
|
+
Args:
|
|
371
|
+
args: Input containing user_id and memory_node_id
|
|
372
|
+
**kwargs: Additional parameters (currently unused)
|
|
373
|
+
|
|
374
|
+
Returns:
|
|
375
|
+
DeleteMemoryOutput containing the request_id
|
|
376
|
+
|
|
377
|
+
Raises:
|
|
378
|
+
MemoryAPIError: If the API request fails
|
|
379
|
+
MemoryNotFoundError: If the memory node is not found
|
|
380
|
+
"""
|
|
381
|
+
logger.info(
|
|
382
|
+
f"Deleting memory node {args.memory_node_id} "
|
|
383
|
+
f"for user {args.user_id}",
|
|
384
|
+
)
|
|
385
|
+
|
|
386
|
+
try:
|
|
387
|
+
# Build URL with path parameter
|
|
388
|
+
url = self.config.get_delete_memory_url(args.memory_node_id)
|
|
389
|
+
|
|
390
|
+
# Send request
|
|
391
|
+
result = await self._request("DELETE", url)
|
|
392
|
+
|
|
393
|
+
# Parse response
|
|
394
|
+
output = DeleteMemoryOutput(
|
|
395
|
+
request_id=result.get("request_id", ""),
|
|
396
|
+
)
|
|
397
|
+
|
|
398
|
+
logger.info(
|
|
399
|
+
f"Successfully deleted memory node {args.memory_node_id}",
|
|
400
|
+
)
|
|
401
|
+
return output
|
|
402
|
+
|
|
403
|
+
except Exception:
|
|
404
|
+
logger.exception(
|
|
405
|
+
f"Failed to delete memory node {args.memory_node_id}",
|
|
406
|
+
)
|
|
407
|
+
raise
|
|
408
|
+
|
|
409
|
+
|
|
410
|
+
class CreateProfileSchema(
|
|
411
|
+
Tool[CreateProfileSchemaInput, CreateProfileSchemaOutput],
|
|
412
|
+
ModelStudioMemoryBase,
|
|
413
|
+
):
|
|
414
|
+
"""
|
|
415
|
+
Component for creating a user profile schema.
|
|
416
|
+
|
|
417
|
+
This component creates a schema that defines the structure of user profiles
|
|
418
|
+
including attribute definitions.
|
|
419
|
+
|
|
420
|
+
Environment Variables:
|
|
421
|
+
DASHSCOPE_API_KEY: Required. API key for authentication
|
|
422
|
+
MODELSTUDIO_SERVICE_ID: Optional. Service identifier
|
|
423
|
+
MEMORY_SERVICE_ENDPOINT: Optional. API endpoint URL
|
|
424
|
+
|
|
425
|
+
Raises:
|
|
426
|
+
ValueError: If DASHSCOPE_API_KEY is not set or if attributes list
|
|
427
|
+
is empty
|
|
428
|
+
MemoryAPIError: If the API request fails
|
|
429
|
+
"""
|
|
430
|
+
|
|
431
|
+
name = "create_profile_schema"
|
|
432
|
+
description = "Create a profile schema with attribute definitions"
|
|
433
|
+
|
|
434
|
+
def __init__(self, config: Optional[MemoryServiceConfig] = None) -> None:
|
|
435
|
+
"""
|
|
436
|
+
Initialize the CreateProfileSchema component.
|
|
437
|
+
|
|
438
|
+
Args:
|
|
439
|
+
config: Optional configuration. If not provided, will be loaded
|
|
440
|
+
from environment variables.
|
|
441
|
+
"""
|
|
442
|
+
Tool.__init__(self)
|
|
443
|
+
ModelStudioMemoryBase.__init__(self, config)
|
|
444
|
+
|
|
445
|
+
async def _arun(
|
|
446
|
+
self,
|
|
447
|
+
args: CreateProfileSchemaInput,
|
|
448
|
+
**kwargs: Any,
|
|
449
|
+
) -> CreateProfileSchemaOutput:
|
|
450
|
+
"""
|
|
451
|
+
Create a profile schema.
|
|
452
|
+
|
|
453
|
+
Args:
|
|
454
|
+
args: Input containing name, description, and attributes
|
|
455
|
+
**kwargs: Additional parameters (currently unused)
|
|
456
|
+
|
|
457
|
+
Returns:
|
|
458
|
+
CreateProfileSchemaOutput containing profile_schema_id and
|
|
459
|
+
request_id
|
|
460
|
+
|
|
461
|
+
Raises:
|
|
462
|
+
MemoryAPIError: If the API request fails
|
|
463
|
+
"""
|
|
464
|
+
logger.info(f"Creating profile schema: {args.name}")
|
|
465
|
+
|
|
466
|
+
try:
|
|
467
|
+
# Build request payload
|
|
468
|
+
payload = args.model_dump(exclude_none=True)
|
|
469
|
+
|
|
470
|
+
# Send request
|
|
471
|
+
result = await self._request(
|
|
472
|
+
"POST",
|
|
473
|
+
self.config.get_create_profile_schema_url(),
|
|
474
|
+
json=payload,
|
|
475
|
+
)
|
|
476
|
+
|
|
477
|
+
# Parse response
|
|
478
|
+
output = CreateProfileSchemaOutput(
|
|
479
|
+
profile_schema_id=result.get("profile_schema_id", ""),
|
|
480
|
+
request_id=result.get("request_id", ""),
|
|
481
|
+
)
|
|
482
|
+
|
|
483
|
+
logger.info(
|
|
484
|
+
f"Successfully created profile schema: "
|
|
485
|
+
f"{output.profile_schema_id}",
|
|
486
|
+
)
|
|
487
|
+
return output
|
|
488
|
+
|
|
489
|
+
except Exception:
|
|
490
|
+
logger.exception(f"Failed to create profile schema: {args.name}")
|
|
491
|
+
raise
|
|
492
|
+
|
|
493
|
+
|
|
494
|
+
class GetUserProfile(
|
|
495
|
+
Tool[GetUserProfileInput, GetUserProfileOutput],
|
|
496
|
+
ModelStudioMemoryBase,
|
|
497
|
+
):
|
|
498
|
+
"""
|
|
499
|
+
Component for retrieving a user profile.
|
|
500
|
+
|
|
501
|
+
This component retrieves a user's profile based on a schema ID and user ID.
|
|
502
|
+
|
|
503
|
+
Environment Variables:
|
|
504
|
+
DASHSCOPE_API_KEY: Required. API key for authentication
|
|
505
|
+
MODELSTUDIO_SERVICE_ID: Optional. Service identifier
|
|
506
|
+
MEMORY_SERVICE_ENDPOINT: Optional. API endpoint URL
|
|
507
|
+
|
|
508
|
+
Raises:
|
|
509
|
+
ValueError: If DASHSCOPE_API_KEY is not set
|
|
510
|
+
MemoryAPIError: If the API request fails
|
|
511
|
+
MemoryNotFoundError: If the profile is not found
|
|
512
|
+
"""
|
|
513
|
+
|
|
514
|
+
name = "get_user_profile"
|
|
515
|
+
description = "Get user profile by schema id and user id"
|
|
516
|
+
|
|
517
|
+
def __init__(self, config: Optional[MemoryServiceConfig] = None) -> None:
|
|
518
|
+
"""
|
|
519
|
+
Initialize the GetUserProfile component.
|
|
520
|
+
|
|
521
|
+
Args:
|
|
522
|
+
config: Optional configuration. If not provided, will be loaded
|
|
523
|
+
from environment variables.
|
|
524
|
+
"""
|
|
525
|
+
Tool.__init__(self)
|
|
526
|
+
ModelStudioMemoryBase.__init__(self, config)
|
|
527
|
+
|
|
528
|
+
async def _arun(
|
|
529
|
+
self,
|
|
530
|
+
args: GetUserProfileInput,
|
|
531
|
+
**kwargs: Any,
|
|
532
|
+
) -> GetUserProfileOutput:
|
|
533
|
+
"""
|
|
534
|
+
Get a user profile.
|
|
535
|
+
|
|
536
|
+
Args:
|
|
537
|
+
args: Input containing schema_id and user_id
|
|
538
|
+
**kwargs: Additional parameters (currently unused)
|
|
539
|
+
|
|
540
|
+
Returns:
|
|
541
|
+
GetUserProfileOutput containing the profile and request_id
|
|
542
|
+
|
|
543
|
+
Raises:
|
|
544
|
+
MemoryAPIError: If the API request fails
|
|
545
|
+
MemoryNotFoundError: If the profile is not found
|
|
546
|
+
"""
|
|
547
|
+
logger.info(
|
|
548
|
+
f"Getting user profile for user {args.user_id} "
|
|
549
|
+
f"with schema {args.schema_id}",
|
|
550
|
+
)
|
|
551
|
+
|
|
552
|
+
try:
|
|
553
|
+
# Build URL with path parameter
|
|
554
|
+
url = self.config.get_user_profile_url(args.schema_id)
|
|
555
|
+
|
|
556
|
+
# Send request with user_id as query parameter
|
|
557
|
+
result = await self._request(
|
|
558
|
+
"GET",
|
|
559
|
+
url,
|
|
560
|
+
params={"user_id": args.user_id},
|
|
561
|
+
)
|
|
562
|
+
|
|
563
|
+
# Parse response - handle API's camelCase field names
|
|
564
|
+
profile_raw = result.get("profile", {})
|
|
565
|
+
attributes = [
|
|
566
|
+
UserProfileAttribute(
|
|
567
|
+
name=item.get("name", ""),
|
|
568
|
+
id=item.get("id", ""),
|
|
569
|
+
value=item.get("value"),
|
|
570
|
+
)
|
|
571
|
+
for item in profile_raw.get("attributes", [])
|
|
572
|
+
]
|
|
573
|
+
|
|
574
|
+
profile = UserProfile(
|
|
575
|
+
schema_description=profile_raw.get("schemaDescription"),
|
|
576
|
+
schema_name=profile_raw.get("schemaName"),
|
|
577
|
+
attributes=attributes,
|
|
578
|
+
)
|
|
579
|
+
|
|
580
|
+
output = GetUserProfileOutput(
|
|
581
|
+
profile=profile,
|
|
582
|
+
request_id=result.get("requestId", ""),
|
|
583
|
+
)
|
|
584
|
+
|
|
585
|
+
logger.info(
|
|
586
|
+
f"Successfully retrieved profile for user {args.user_id}",
|
|
587
|
+
)
|
|
588
|
+
return output
|
|
589
|
+
|
|
590
|
+
except Exception:
|
|
591
|
+
logger.exception(
|
|
592
|
+
f"Failed to get profile for user {args.user_id}",
|
|
593
|
+
)
|
|
594
|
+
raise
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
Custom exceptions for ModelStudio Memory components.
|
|
4
|
+
"""
|
|
5
|
+
from typing import Optional
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class MemoryAPIError(Exception):
|
|
9
|
+
"""
|
|
10
|
+
Base exception for Memory API errors.
|
|
11
|
+
|
|
12
|
+
Attributes:
|
|
13
|
+
message: Error message
|
|
14
|
+
status_code: HTTP status code
|
|
15
|
+
error_code: API error code (e.g., 'InvalidApiKey', 'InvalidParameter')
|
|
16
|
+
request_id: Request ID for tracking
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
def __init__(
|
|
20
|
+
self,
|
|
21
|
+
message: str,
|
|
22
|
+
status_code: Optional[int] = None,
|
|
23
|
+
error_code: Optional[str] = None,
|
|
24
|
+
request_id: Optional[str] = None,
|
|
25
|
+
):
|
|
26
|
+
self.status_code = status_code
|
|
27
|
+
self.error_code = error_code
|
|
28
|
+
self.request_id = request_id
|
|
29
|
+
super().__init__(message)
|
|
30
|
+
|
|
31
|
+
def __str__(self) -> str:
|
|
32
|
+
"""Format error message with all available information."""
|
|
33
|
+
parts = [super().__str__()]
|
|
34
|
+
|
|
35
|
+
if self.error_code:
|
|
36
|
+
parts.append(f"Error Code: {self.error_code}")
|
|
37
|
+
|
|
38
|
+
if self.status_code:
|
|
39
|
+
parts.append(f"Status Code: {self.status_code}")
|
|
40
|
+
|
|
41
|
+
if self.request_id:
|
|
42
|
+
parts.append(f"Request ID: {self.request_id}")
|
|
43
|
+
|
|
44
|
+
return " | ".join(parts)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class MemoryAuthenticationError(MemoryAPIError):
|
|
48
|
+
"""Raised when authentication fails (401, 403)."""
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class MemoryNotFoundError(MemoryAPIError):
|
|
52
|
+
"""Raised when a memory node is not found (404)."""
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class MemoryValidationError(MemoryAPIError):
|
|
56
|
+
"""Raised when input validation fails (400)."""
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class MemoryNetworkError(MemoryAPIError):
|
|
60
|
+
"""Raised when network communication fails."""
|