agentscope-runtime 0.1.5b2__py3-none-any.whl → 0.2.0__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 (107) hide show
  1. agentscope_runtime/common/__init__.py +0 -0
  2. agentscope_runtime/common/collections/in_memory_mapping.py +27 -0
  3. agentscope_runtime/common/collections/redis_mapping.py +42 -0
  4. agentscope_runtime/common/container_clients/__init__.py +0 -0
  5. agentscope_runtime/common/container_clients/agentrun_client.py +1098 -0
  6. agentscope_runtime/common/container_clients/docker_client.py +250 -0
  7. agentscope_runtime/{sandbox/manager → common}/container_clients/kubernetes_client.py +6 -13
  8. agentscope_runtime/engine/__init__.py +12 -0
  9. agentscope_runtime/engine/agents/agentscope_agent.py +567 -0
  10. agentscope_runtime/engine/agents/agno_agent.py +26 -27
  11. agentscope_runtime/engine/agents/autogen_agent.py +13 -8
  12. agentscope_runtime/engine/agents/langgraph_agent.py +52 -9
  13. agentscope_runtime/engine/agents/utils.py +53 -0
  14. agentscope_runtime/engine/app/__init__.py +6 -0
  15. agentscope_runtime/engine/app/agent_app.py +239 -0
  16. agentscope_runtime/engine/app/base_app.py +181 -0
  17. agentscope_runtime/engine/app/celery_mixin.py +92 -0
  18. agentscope_runtime/engine/deployers/adapter/responses/response_api_adapter_utils.py +5 -1
  19. agentscope_runtime/engine/deployers/base.py +1 -0
  20. agentscope_runtime/engine/deployers/cli_fc_deploy.py +39 -20
  21. agentscope_runtime/engine/deployers/kubernetes_deployer.py +12 -5
  22. agentscope_runtime/engine/deployers/local_deployer.py +61 -3
  23. agentscope_runtime/engine/deployers/modelstudio_deployer.py +201 -40
  24. agentscope_runtime/engine/deployers/utils/docker_image_utils/runner_image_factory.py +9 -0
  25. agentscope_runtime/engine/deployers/utils/package_project_utils.py +234 -3
  26. agentscope_runtime/engine/deployers/utils/service_utils/fastapi_factory.py +567 -7
  27. agentscope_runtime/engine/deployers/utils/service_utils/standalone_main.py.j2 +211 -0
  28. agentscope_runtime/engine/deployers/utils/wheel_packager.py +1 -1
  29. agentscope_runtime/engine/helpers/helper.py +60 -41
  30. agentscope_runtime/engine/runner.py +40 -24
  31. agentscope_runtime/engine/schemas/agent_schemas.py +42 -0
  32. agentscope_runtime/engine/schemas/modelstudio_llm.py +14 -14
  33. agentscope_runtime/engine/services/sandbox_service.py +62 -70
  34. agentscope_runtime/engine/services/tablestore_memory_service.py +307 -0
  35. agentscope_runtime/engine/services/tablestore_rag_service.py +143 -0
  36. agentscope_runtime/engine/services/tablestore_session_history_service.py +293 -0
  37. agentscope_runtime/engine/services/utils/__init__.py +0 -0
  38. agentscope_runtime/engine/services/utils/tablestore_service_utils.py +352 -0
  39. agentscope_runtime/engine/tracing/__init__.py +9 -3
  40. agentscope_runtime/engine/tracing/asyncio_util.py +24 -0
  41. agentscope_runtime/engine/tracing/base.py +66 -34
  42. agentscope_runtime/engine/tracing/local_logging_handler.py +45 -31
  43. agentscope_runtime/engine/tracing/message_util.py +528 -0
  44. agentscope_runtime/engine/tracing/tracing_metric.py +20 -8
  45. agentscope_runtime/engine/tracing/tracing_util.py +130 -0
  46. agentscope_runtime/engine/tracing/wrapper.py +794 -169
  47. agentscope_runtime/sandbox/__init__.py +2 -0
  48. agentscope_runtime/sandbox/box/base/__init__.py +4 -0
  49. agentscope_runtime/sandbox/box/base/base_sandbox.py +6 -4
  50. agentscope_runtime/sandbox/box/browser/__init__.py +4 -0
  51. agentscope_runtime/sandbox/box/browser/browser_sandbox.py +10 -14
  52. agentscope_runtime/sandbox/box/dummy/__init__.py +4 -0
  53. agentscope_runtime/sandbox/box/dummy/dummy_sandbox.py +2 -1
  54. agentscope_runtime/sandbox/box/filesystem/__init__.py +4 -0
  55. agentscope_runtime/sandbox/box/filesystem/filesystem_sandbox.py +10 -7
  56. agentscope_runtime/sandbox/box/gui/__init__.py +4 -0
  57. agentscope_runtime/sandbox/box/gui/box/__init__.py +0 -0
  58. agentscope_runtime/sandbox/box/gui/gui_sandbox.py +81 -0
  59. agentscope_runtime/sandbox/box/sandbox.py +5 -2
  60. agentscope_runtime/sandbox/box/shared/routers/generic.py +20 -1
  61. agentscope_runtime/sandbox/box/training_box/__init__.py +4 -0
  62. agentscope_runtime/sandbox/box/training_box/training_box.py +7 -54
  63. agentscope_runtime/sandbox/build.py +143 -58
  64. agentscope_runtime/sandbox/client/http_client.py +87 -59
  65. agentscope_runtime/sandbox/client/training_client.py +0 -1
  66. agentscope_runtime/sandbox/constant.py +27 -1
  67. agentscope_runtime/sandbox/custom/custom_sandbox.py +7 -6
  68. agentscope_runtime/sandbox/custom/example.py +4 -3
  69. agentscope_runtime/sandbox/enums.py +1 -1
  70. agentscope_runtime/sandbox/manager/sandbox_manager.py +212 -106
  71. agentscope_runtime/sandbox/manager/server/app.py +82 -14
  72. agentscope_runtime/sandbox/manager/server/config.py +50 -3
  73. agentscope_runtime/sandbox/model/container.py +12 -23
  74. agentscope_runtime/sandbox/model/manager_config.py +93 -5
  75. agentscope_runtime/sandbox/registry.py +1 -1
  76. agentscope_runtime/sandbox/tools/gui/__init__.py +7 -0
  77. agentscope_runtime/sandbox/tools/gui/tool.py +77 -0
  78. agentscope_runtime/sandbox/tools/mcp_tool.py +6 -2
  79. agentscope_runtime/sandbox/tools/tool.py +4 -0
  80. agentscope_runtime/sandbox/utils.py +124 -0
  81. agentscope_runtime/version.py +1 -1
  82. {agentscope_runtime-0.1.5b2.dist-info → agentscope_runtime-0.2.0.dist-info}/METADATA +246 -111
  83. {agentscope_runtime-0.1.5b2.dist-info → agentscope_runtime-0.2.0.dist-info}/RECORD +96 -80
  84. agentscope_runtime/engine/agents/agentscope_agent/__init__.py +0 -6
  85. agentscope_runtime/engine/agents/agentscope_agent/agent.py +0 -401
  86. agentscope_runtime/engine/agents/agentscope_agent/hooks.py +0 -169
  87. agentscope_runtime/engine/agents/llm_agent.py +0 -51
  88. agentscope_runtime/engine/llms/__init__.py +0 -3
  89. agentscope_runtime/engine/llms/base_llm.py +0 -60
  90. agentscope_runtime/engine/llms/qwen_llm.py +0 -47
  91. agentscope_runtime/sandbox/manager/collections/in_memory_mapping.py +0 -22
  92. agentscope_runtime/sandbox/manager/collections/redis_mapping.py +0 -26
  93. agentscope_runtime/sandbox/manager/container_clients/__init__.py +0 -10
  94. agentscope_runtime/sandbox/manager/container_clients/docker_client.py +0 -422
  95. /agentscope_runtime/{sandbox/manager → common}/collections/__init__.py +0 -0
  96. /agentscope_runtime/{sandbox/manager → common}/collections/base_mapping.py +0 -0
  97. /agentscope_runtime/{sandbox/manager → common}/collections/base_queue.py +0 -0
  98. /agentscope_runtime/{sandbox/manager → common}/collections/base_set.py +0 -0
  99. /agentscope_runtime/{sandbox/manager → common}/collections/in_memory_queue.py +0 -0
  100. /agentscope_runtime/{sandbox/manager → common}/collections/in_memory_set.py +0 -0
  101. /agentscope_runtime/{sandbox/manager → common}/collections/redis_queue.py +0 -0
  102. /agentscope_runtime/{sandbox/manager → common}/collections/redis_set.py +0 -0
  103. /agentscope_runtime/{sandbox/manager → common}/container_clients/base_client.py +0 -0
  104. {agentscope_runtime-0.1.5b2.dist-info → agentscope_runtime-0.2.0.dist-info}/WHEEL +0 -0
  105. {agentscope_runtime-0.1.5b2.dist-info → agentscope_runtime-0.2.0.dist-info}/entry_points.txt +0 -0
  106. {agentscope_runtime-0.1.5b2.dist-info → agentscope_runtime-0.2.0.dist-info}/licenses/LICENSE +0 -0
  107. {agentscope_runtime-0.1.5b2.dist-info → agentscope_runtime-0.2.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,293 @@
1
+ # -*- coding: utf-8 -*-
2
+ # pylint: disable=redefined-outer-name
3
+ import asyncio
4
+ import uuid
5
+ from typing import Any, Dict, List, Optional, Union
6
+
7
+ try:
8
+ import tablestore
9
+ from tablestore import AsyncOTSClient as AsyncTablestoreClient
10
+ from tablestore_for_agent_memory.base.base_memory_store import (
11
+ Session as TablestoreSession,
12
+ )
13
+ from tablestore_for_agent_memory.base.common import MetaType, Order
14
+ from tablestore_for_agent_memory.memory.async_memory_store import (
15
+ AsyncMemoryStore,
16
+ )
17
+ except ImportError as e:
18
+ raise ImportError(
19
+ "aliyun_tablestore is not available. "
20
+ "Please run pip install agentscope-runtime[aliyun_tablestore_ext]",
21
+ ) from e
22
+
23
+ from ..schemas.agent_schemas import Message
24
+ from .session_history_service import Session, SessionHistoryService
25
+ from .utils.tablestore_service_utils import (
26
+ convert_message_to_tablestore_message,
27
+ convert_tablestore_session_to_session,
28
+ tablestore_log,
29
+ )
30
+
31
+
32
+ class TablestoreSessionHistoryService(SessionHistoryService):
33
+ """An aliyun tablestore implementation of the SessionHistoryService
34
+ based on tablestore_for_agent_memory
35
+ (https://github.com/aliyun/
36
+ alibabacloud-tablestore-for-agent-memory/blob/main/python/docs/memory_store_tutorial.ipynb).
37
+ """
38
+
39
+ _SESSION_SECONDARY_INDEX_NAME = (
40
+ "agentscope_runtime_session_secondary_index"
41
+ )
42
+ _SESSION_SEARCH_INDEX_NAME = "agentscope_runtime_session_search_index"
43
+ _MESSAGE_SECONDARY_INDEX_NAME = (
44
+ "agentscope_runtime_message_secondary_index"
45
+ )
46
+ _MESSAGE_SEARCH_INDEX_NAME = "agentscope_runtime_message_search_index"
47
+
48
+ def __init__(
49
+ self,
50
+ tablestore_client: AsyncTablestoreClient,
51
+ session_table_name: Optional[str] = "agentscope_runtime_session",
52
+ message_table_name: Optional[str] = "agentscope_runtime_message",
53
+ session_secondary_index_meta: Optional[Dict[str, MetaType]] = None,
54
+ session_search_index_schema: Optional[
55
+ List[tablestore.FieldSchema]
56
+ ] = None,
57
+ message_search_index_schema: Optional[
58
+ List[tablestore.FieldSchema]
59
+ ] = None,
60
+ **kwargs: Any,
61
+ ) -> None:
62
+ """Initializes the TablestoreSessionHistoryService."""
63
+ self._tablestore_client = tablestore_client
64
+ self._session_table_name = session_table_name
65
+ self._message_table_name = message_table_name
66
+ self._session_secondary_index_meta = session_secondary_index_meta
67
+ self._session_search_index_schema = session_search_index_schema
68
+ self._message_search_index_schema = message_search_index_schema
69
+ self._memory_store: Optional[AsyncMemoryStore] = None
70
+ self._memory_store_init_parameter_kwargs = kwargs
71
+
72
+ async def _init_memory_store(self) -> None:
73
+ self._memory_store = AsyncMemoryStore(
74
+ tablestore_client=self._tablestore_client,
75
+ session_table_name=self._session_table_name,
76
+ message_table_name=self._message_table_name,
77
+ session_secondary_index_name=self._SESSION_SECONDARY_INDEX_NAME,
78
+ session_search_index_name=self._SESSION_SEARCH_INDEX_NAME,
79
+ message_secondary_index_name=self._MESSAGE_SECONDARY_INDEX_NAME,
80
+ message_search_index_name=self._MESSAGE_SEARCH_INDEX_NAME,
81
+ session_secondary_index_meta=self._session_secondary_index_meta,
82
+ session_search_index_schema=self._session_search_index_schema,
83
+ message_search_index_schema=self._message_search_index_schema,
84
+ **self._memory_store_init_parameter_kwargs,
85
+ )
86
+
87
+ await self._memory_store.init_table()
88
+ await self._memory_store.init_search_index()
89
+
90
+ async def start(self) -> None:
91
+ """Start the tablestore service"""
92
+ if self._memory_store:
93
+ return
94
+ await self._init_memory_store()
95
+
96
+ async def stop(self) -> None:
97
+ """Close the tablestore service"""
98
+ if self._memory_store is None:
99
+ return
100
+ memory_store = self._memory_store
101
+ self._memory_store = None
102
+ await memory_store.close()
103
+
104
+ async def health(self) -> bool:
105
+ """Checks the health of the service."""
106
+ if self._memory_store is None:
107
+ tablestore_log(
108
+ "Tablestore session history service is not started.",
109
+ )
110
+ return False
111
+
112
+ try:
113
+ async for _ in await self._memory_store.list_all_sessions():
114
+ return True
115
+ return True
116
+ except Exception as e:
117
+ tablestore_log(
118
+ f"Tablestore session history service "
119
+ f"cannot access Tablestore, error: {str(e)}.",
120
+ )
121
+ return False
122
+
123
+ async def create_session(
124
+ self,
125
+ user_id: str,
126
+ session_id: Optional[str] = None,
127
+ ) -> Session:
128
+ """Creates a new session for a given user and stores it.
129
+
130
+ Args:
131
+ user_id: The identifier for the user creating the session.
132
+ session_id: The identifier for the session to delete.
133
+
134
+ Returns:
135
+ A newly created Session object.
136
+ """
137
+ session_id = (
138
+ session_id.strip()
139
+ if session_id and session_id.strip()
140
+ else str(uuid.uuid4())
141
+ )
142
+ tablestore_session = TablestoreSession(
143
+ session_id=session_id,
144
+ user_id=user_id,
145
+ )
146
+
147
+ await self._memory_store.put_session(tablestore_session)
148
+ return convert_tablestore_session_to_session(tablestore_session)
149
+
150
+ async def get_session(
151
+ self,
152
+ user_id: str,
153
+ session_id: str,
154
+ ) -> Session | None:
155
+ """Retrieves a specific session from memory.
156
+
157
+ Args:
158
+ user_id: The identifier for the user.
159
+ session_id: The identifier for the session to retrieve.
160
+
161
+ Returns:
162
+ A Session object if found, otherwise None.
163
+ """
164
+
165
+ tablestore_session = await self._memory_store.get_session(
166
+ user_id=user_id,
167
+ session_id=session_id,
168
+ )
169
+
170
+ if not tablestore_session:
171
+ tablestore_session = TablestoreSession(
172
+ session_id=session_id,
173
+ user_id=user_id,
174
+ )
175
+ await self._memory_store.put_session(tablestore_session)
176
+ tablestore_messages = None
177
+ else:
178
+ messages_iterator = await self._memory_store.list_messages(
179
+ session_id=session_id,
180
+ order=Order.ASC,
181
+ # Sort by timestamp,
182
+ # keeping the most recent information at the end of the list.
183
+ )
184
+ tablestore_messages = [
185
+ message async for message in messages_iterator
186
+ ]
187
+
188
+ return convert_tablestore_session_to_session(
189
+ tablestore_session,
190
+ tablestore_messages,
191
+ )
192
+
193
+ async def delete_session(self, user_id: str, session_id: str) -> None:
194
+ """Deletes a specific session from memory.
195
+
196
+ If the session does not exist, the method does nothing.
197
+
198
+ Args:
199
+ user_id: The identifier for the user.
200
+ session_id: The identifier for the session to delete.
201
+ """
202
+ await self._memory_store.delete_session_and_messages(
203
+ user_id=user_id,
204
+ session_id=session_id,
205
+ )
206
+
207
+ async def list_sessions(self, user_id: str) -> list[Session]:
208
+ """Lists all sessions for a given user.
209
+
210
+ To improve performance and reduce data transfer, the returned session
211
+ objects do not contain the detailed response history.
212
+
213
+ Args:
214
+ user_id: The identifier of the user whose sessions to list.
215
+
216
+ Returns:
217
+ A list of Session objects belonging to the user, without history.
218
+ """
219
+ tablestore_sessions = await self._memory_store.list_sessions(user_id)
220
+ return [
221
+ convert_tablestore_session_to_session(tablestore_session)
222
+ async for tablestore_session in tablestore_sessions
223
+ ]
224
+
225
+ async def append_message(
226
+ self,
227
+ session: Session,
228
+ message: Union[
229
+ Message,
230
+ List[Message],
231
+ Dict[str, Any],
232
+ List[Dict[str, Any]],
233
+ ],
234
+ ) -> None:
235
+ """Appends message to a session's history in memory.
236
+
237
+ This method finds the authoritative session object in the in-memory
238
+ storage and appends the message to its history. It supports both
239
+ dictionary format messages and Message objects.
240
+
241
+ Args:
242
+ session: The session object, typically from the context. The
243
+ user_id and id from this object are used for lookup.
244
+ message: The message or list of messages to append to the
245
+ session's history.
246
+ """
247
+ # Normalize to list
248
+ if not isinstance(message, list):
249
+ message = [message]
250
+
251
+ norm_message = []
252
+ for msg in message:
253
+ if msg is None:
254
+ continue
255
+
256
+ if not isinstance(msg, Message):
257
+ msg = Message.model_validate(msg)
258
+ norm_message.append(msg)
259
+ session.messages.extend(norm_message)
260
+
261
+ tablestore_session = await self._memory_store.get_session(
262
+ session_id=session.id,
263
+ user_id=session.user_id,
264
+ )
265
+ if tablestore_session:
266
+ put_tasks = [
267
+ self._memory_store.put_message(
268
+ convert_message_to_tablestore_message(message, session),
269
+ )
270
+ for message in norm_message
271
+ ]
272
+ await asyncio.gather(*put_tasks)
273
+
274
+ else:
275
+ tablestore_log(
276
+ f"Warning: Session {session.id} not found "
277
+ f"in tablestore storage for "
278
+ f"append_message.",
279
+ )
280
+
281
+ async def delete_user_sessions(self, user_id: str) -> None:
282
+ """
283
+ Deletes all session history data for a specific user.
284
+
285
+ Args:
286
+ user_id (str): The ID of the user whose session history data should
287
+ be deleted
288
+ """
289
+ delete_tasks = [
290
+ self.delete_session(user_id, session.id)
291
+ for session in (await self.list_sessions(user_id=user_id))
292
+ ]
293
+ await asyncio.gather(*delete_tasks)
File without changes
@@ -0,0 +1,352 @@
1
+ # -*- coding: utf-8 -*-
2
+ import copy
3
+ import json
4
+ from typing import Any, Dict, List, Optional, Tuple
5
+
6
+ import tablestore
7
+ from langchain_core.embeddings import Embeddings
8
+ from tablestore import AsyncOTSClient as AsyncTablestoreClient
9
+ from tablestore.credentials import CredentialsProvider
10
+ from tablestore_for_agent_memory.base.base_knowledge_store import (
11
+ Document as TablestoreDocument,
12
+ )
13
+ from tablestore_for_agent_memory.base.base_memory_store import (
14
+ Message as TablestoreMessage,
15
+ )
16
+ from tablestore_for_agent_memory.base.base_memory_store import (
17
+ Session as TablestoreSession,
18
+ )
19
+
20
+ from ...schemas.agent_schemas import ContentType, MessageType
21
+ from ..session_history_service import Message, Session
22
+
23
+
24
+ def create_tablestore_client(
25
+ end_point: str,
26
+ access_key_id: str,
27
+ access_key_secret: str,
28
+ instance_name: str,
29
+ sts_token: Optional[str] = None,
30
+ region: Optional[str] = None,
31
+ credentials_provider: Optional[CredentialsProvider] = None,
32
+ retry_policy: tablestore.RetryPolicy = tablestore.WriteRetryPolicy(),
33
+ **kwargs: Any,
34
+ ) -> AsyncTablestoreClient:
35
+ return AsyncTablestoreClient(
36
+ end_point=end_point,
37
+ access_key_id=access_key_id,
38
+ access_key_secret=access_key_secret,
39
+ instance_name=instance_name,
40
+ region=region,
41
+ credentials_provider=credentials_provider,
42
+ sts_token=None if sts_token == "" else sts_token,
43
+ retry_policy=retry_policy,
44
+ **kwargs,
45
+ )
46
+
47
+
48
+ content_list_name = "content_list"
49
+
50
+
51
+ def exclude_None_fields_in_place(obj: Dict):
52
+ """Remove fields with None values from dictionary in-place"""
53
+ obj_copy = copy.deepcopy(obj)
54
+ for key, value in obj_copy.items():
55
+ if value is None:
56
+ del obj[key]
57
+
58
+
59
+ def tablestore_log(msg: str):
60
+ print(msg)
61
+
62
+
63
+ def convert_tablestore_session_to_session(
64
+ tablestore_session: TablestoreSession,
65
+ tablestore_messages: Optional[List[TablestoreMessage]] = None,
66
+ ) -> Session:
67
+ """Convert TablestoreSession to Session"""
68
+ init_json = _generate_init_json_from_tablestore_session(
69
+ tablestore_session,
70
+ tablestore_messages,
71
+ )
72
+ return Session.model_validate(init_json)
73
+
74
+
75
+ # now, the func is not be used,
76
+ # because the interface of session history service don't need this func,
77
+ # just for future
78
+ def convert_session_to_tablestore_session(
79
+ session: Session,
80
+ ) -> Tuple[TablestoreSession, List[TablestoreMessage]]:
81
+ """Convert Session to TablestoreSession and list of TablestoreMessage"""
82
+ tablestore_session_metadata = session.model_dump(
83
+ exclude={"id", "user_id", "messages"},
84
+ )
85
+ exclude_None_fields_in_place(tablestore_session_metadata)
86
+ tablestore_session = TablestoreSession(
87
+ user_id=session.user_id,
88
+ session_id=session.id,
89
+ metadata=tablestore_session_metadata,
90
+ )
91
+ tablestore_messages = [
92
+ convert_message_to_tablestore_message(message, session)
93
+ for message in session.messages
94
+ ]
95
+
96
+ return tablestore_session, tablestore_messages
97
+
98
+
99
+ def convert_tablestore_message_to_message(
100
+ tablestore_message: TablestoreMessage,
101
+ ) -> Message:
102
+ """Convert TablestoreMessage to Message"""
103
+ init_json = _generate_init_json_from_tablestore_message(tablestore_message)
104
+ return Message.model_validate(init_json)
105
+
106
+
107
+ def convert_message_to_tablestore_message(
108
+ message: Message,
109
+ session: Session,
110
+ ) -> TablestoreMessage:
111
+ """Convert Message to TablestoreMessage"""
112
+ content, content_list = _generate_tablestore_content_from_message(message)
113
+ tablestore_message_metadata = message.model_dump(exclude={"content", "id"})
114
+ tablestore_message_metadata[content_list_name] = json.dumps(
115
+ content_list,
116
+ ensure_ascii=False,
117
+ )
118
+ exclude_None_fields_in_place(tablestore_message_metadata)
119
+ tablestore_message = TablestoreMessage(
120
+ session_id=session.id,
121
+ message_id=message.id,
122
+ content=content,
123
+ metadata=tablestore_message_metadata,
124
+ )
125
+ return tablestore_message
126
+
127
+
128
+ # This function is designed to
129
+ # facilitate batch embedding computation for better performance.
130
+ def convert_messages_to_tablestore_documents(
131
+ messages: List[Message],
132
+ user_id: str,
133
+ session_id: str,
134
+ embedding_model: Optional[Embeddings] = None,
135
+ ) -> List[TablestoreDocument]:
136
+ """Convert list of messages
137
+ to TablestoreDocuments with optional batch embedding"""
138
+ if not embedding_model:
139
+ return [
140
+ convert_message_to_tablestore_document(
141
+ message,
142
+ user_id,
143
+ session_id,
144
+ )
145
+ for message in messages
146
+ ]
147
+
148
+ # Batch embed messages: extract content, filter non-empty,
149
+ # compute embeddings, and align results with original messages
150
+ contents = [
151
+ _generate_tablestore_content_from_message(message)[0]
152
+ for message in messages
153
+ ]
154
+ contents_not_none = [
155
+ content for content in contents if content is not None
156
+ ]
157
+
158
+ embeddings_not_none = embedding_model.embed_documents(contents_not_none)
159
+ embeddings = []
160
+ index = 0
161
+ for content in contents:
162
+ if content is not None:
163
+ embeddings.append(embeddings_not_none[index])
164
+ index += 1
165
+ continue
166
+ embeddings.append(None)
167
+
168
+ return [
169
+ convert_message_to_tablestore_document(
170
+ message,
171
+ user_id,
172
+ session_id,
173
+ embedding,
174
+ )
175
+ for message, embedding in zip(messages, embeddings)
176
+ ]
177
+
178
+
179
+ def convert_message_to_tablestore_document(
180
+ message: Message,
181
+ user_id: str,
182
+ session_id: str,
183
+ embedding: Optional[List[float]] = None,
184
+ ) -> TablestoreDocument:
185
+ """Convert Message to TablestoreDocument"""
186
+ content, content_list = _generate_tablestore_content_from_message(message)
187
+ tablestore_document_metadata = message.model_dump(
188
+ exclude={"content", "id"},
189
+ )
190
+ tablestore_document_metadata.update(
191
+ {
192
+ "user_id": user_id,
193
+ "session_id": session_id,
194
+ content_list_name: json.dumps(content_list, ensure_ascii=False),
195
+ },
196
+ )
197
+ exclude_None_fields_in_place(tablestore_document_metadata)
198
+ tablestore_document = TablestoreDocument(
199
+ document_id=message.id,
200
+ text=content,
201
+ embedding=embedding if embedding else None,
202
+ metadata=tablestore_document_metadata,
203
+ )
204
+ return tablestore_document
205
+
206
+
207
+ def convert_tablestore_document_to_message(
208
+ tablestore_document: TablestoreDocument,
209
+ ) -> Message:
210
+ """Convert TablestoreDocument to Message"""
211
+ init_json = _generate_init_json_from_tablestore_document(
212
+ tablestore_document,
213
+ )
214
+ return Message.model_validate(init_json)
215
+
216
+
217
+ def _generate_init_json_from_tablestore_session(
218
+ tablestore_session: TablestoreSession,
219
+ tablestore_messages: Optional[List[TablestoreMessage]] = None,
220
+ ) -> Dict[str, Any]:
221
+ """Generate initialization JSON from TablestoreSession"""
222
+ init_json = {
223
+ "id": tablestore_session.session_id,
224
+ "user_id": tablestore_session.user_id,
225
+ "messages": (
226
+ [
227
+ convert_tablestore_message_to_message(tablestore_message)
228
+ for tablestore_message in tablestore_messages
229
+ ]
230
+ if tablestore_messages is not None
231
+ else []
232
+ ),
233
+ }
234
+ # for fit future, having more fields in Session
235
+ init_json.update(tablestore_session.metadata)
236
+ return init_json
237
+
238
+
239
+ def _generate_init_json_from_tablestore_message(
240
+ tablestore_message: TablestoreMessage,
241
+ ) -> Dict[str, Any]:
242
+ """Generate initialization JSON from TablestoreMessage"""
243
+ tablestore_message = copy.deepcopy(tablestore_message)
244
+ tablestore_message_content_list = tablestore_message.metadata.pop(
245
+ content_list_name,
246
+ None,
247
+ )
248
+ init_json = {
249
+ "id": tablestore_message.message_id,
250
+ "content": _generate_content_from_tablestore_content(
251
+ text=tablestore_message.content,
252
+ content_list=(
253
+ json.loads(tablestore_message_content_list)
254
+ if tablestore_message_content_list
255
+ else None
256
+ ),
257
+ ),
258
+ }
259
+ init_json.update(tablestore_message.metadata)
260
+ return init_json
261
+
262
+
263
+ def _generate_init_json_from_tablestore_document(
264
+ tablestore_document: TablestoreDocument,
265
+ ) -> Dict[str, Any]:
266
+ """Generate initialization JSON from TablestoreDocument"""
267
+ tablestore_document = copy.deepcopy(tablestore_document)
268
+ tablestore_document_content_list = tablestore_document.metadata.pop(
269
+ content_list_name,
270
+ None,
271
+ )
272
+ init_json = {
273
+ "id": tablestore_document.document_id,
274
+ "content": _generate_content_from_tablestore_content(
275
+ text=tablestore_document.text,
276
+ content_list=(
277
+ json.loads(tablestore_document_content_list)
278
+ if tablestore_document_content_list
279
+ else None
280
+ ),
281
+ ),
282
+ }
283
+ init_json.update(tablestore_document.metadata)
284
+ return init_json
285
+
286
+
287
+ def _generate_content_from_tablestore_content(
288
+ text: str,
289
+ content_list: List[Dict[str, Any]],
290
+ ) -> Optional[List[Dict[str, Any]]]:
291
+ """Generate final content from text and content list"""
292
+ content_list = copy.deepcopy(content_list)
293
+
294
+ if text is None:
295
+ return content_list
296
+
297
+ for content in content_list:
298
+ if content["type"] == ContentType.TEXT:
299
+ content["text"] = text
300
+ break
301
+ return content_list
302
+
303
+
304
+ def _generate_tablestore_content_from_message(
305
+ message: Message,
306
+ ) -> Tuple[Optional[str], Optional[List[Dict[str, Any]]]]:
307
+ """Generate Tablestore content (text and content list) from Message"""
308
+ if message.content is None:
309
+ return None, None
310
+
311
+ content_json_list = [content.model_dump() for content in message.content]
312
+ content = None
313
+
314
+ if message.type != MessageType.MESSAGE:
315
+ return content, content_json_list
316
+
317
+ for content_json in content_json_list:
318
+ if content_json["type"] == ContentType.TEXT:
319
+ content = content_json.pop("text")
320
+ break
321
+
322
+ return content, content_json_list
323
+
324
+
325
+ # This global variable will be cached to reduce computation time overhead
326
+ message_metadata_names: Optional[List[str]] = None
327
+
328
+
329
+ def get_message_metadata_names():
330
+ """Get list of message metadata field names"""
331
+ global message_metadata_names
332
+
333
+ if message_metadata_names is not None:
334
+ return message_metadata_names
335
+
336
+ message_metadata_names = list(Message.model_fields.keys())
337
+
338
+ message_metadata_exclude_names = ("id", "content")
339
+ message_metadata_extra_names = (
340
+ "document_id",
341
+ "text",
342
+ "user_id",
343
+ "session_id",
344
+ content_list_name,
345
+ )
346
+
347
+ for exclude_name in message_metadata_exclude_names:
348
+ message_metadata_names.remove(exclude_name)
349
+ for extra_name in message_metadata_extra_names:
350
+ message_metadata_names.append(extra_name)
351
+
352
+ return message_metadata_names
@@ -3,6 +3,14 @@ from typing import Any, List, Union
3
3
 
4
4
  from .base import BaseLogHandler, Tracer, TracerHandler
5
5
  from .tracing_metric import TraceType
6
+ from .tracing_util import TracingUtil
7
+ from .wrapper import trace
8
+
9
+ __all__ = [
10
+ "trace",
11
+ "TraceType",
12
+ "TracingUtil",
13
+ ]
6
14
 
7
15
 
8
16
  def create_handler(
@@ -15,9 +23,7 @@ def create_handler(
15
23
  if "default" in eval_mode:
16
24
  handlers.append(BaseLogHandler())
17
25
  elif "local_logging" in eval_mode:
18
- from .local_logging_handler import (
19
- LocalLogHandler,
20
- )
26
+ from .local_logging_handler import LocalLogHandler
21
27
 
22
28
  handlers.append(LocalLogHandler(**eval_params))
23
29
  return handlers
@@ -0,0 +1,24 @@
1
+ # -*- coding: utf-8 -*-
2
+ from typing import AsyncIterable, AsyncIterator, Tuple, TypeVar
3
+
4
+ T_co = TypeVar("T_co", covariant=True)
5
+
6
+
7
+ async def aenumerate(
8
+ asequence: AsyncIterable[T_co],
9
+ start: int = 0,
10
+ ) -> AsyncIterator[Tuple[int, T_co]]:
11
+ """Asynchronously enumerate an async iterator from a given start value.
12
+
13
+ Args:
14
+ asequence (AsyncIterable[T_co]): The async iterable to enumerate.
15
+ start (int): The starting value for enumeration. Defaults to 0.
16
+
17
+ Yields:
18
+ Tuple[int, T_co]: A tuple containing the index and the item from the
19
+ async iterable.
20
+ """
21
+ n = start
22
+ async for elem in asequence:
23
+ yield n, elem
24
+ n += 1