agentscope-runtime 0.1.3__py3-none-any.whl → 0.1.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.
Files changed (49) hide show
  1. agentscope_runtime/engine/agents/agentscope_agent/agent.py +56 -12
  2. agentscope_runtime/engine/agents/agentscope_agent/hooks.py +2 -1
  3. agentscope_runtime/engine/agents/agno_agent.py +11 -5
  4. agentscope_runtime/engine/agents/autogen_agent.py +10 -4
  5. agentscope_runtime/engine/agents/utils.py +53 -0
  6. agentscope_runtime/engine/services/context_manager.py +2 -0
  7. agentscope_runtime/engine/services/mem0_memory_service.py +124 -0
  8. agentscope_runtime/engine/services/memory_service.py +2 -1
  9. agentscope_runtime/engine/services/redis_session_history_service.py +4 -3
  10. agentscope_runtime/engine/services/sandbox_service.py +6 -16
  11. agentscope_runtime/engine/services/session_history_service.py +4 -3
  12. agentscope_runtime/engine/services/tablestore_memory_service.py +304 -0
  13. agentscope_runtime/engine/services/tablestore_rag_service.py +143 -0
  14. agentscope_runtime/engine/services/tablestore_session_history_service.py +293 -0
  15. agentscope_runtime/engine/services/utils/__init__.py +0 -0
  16. agentscope_runtime/engine/services/utils/tablestore_service_utils.py +352 -0
  17. agentscope_runtime/sandbox/box/base/base_sandbox.py +2 -2
  18. agentscope_runtime/sandbox/box/browser/browser_sandbox.py +2 -2
  19. agentscope_runtime/sandbox/box/filesystem/filesystem_sandbox.py +2 -2
  20. agentscope_runtime/sandbox/box/training_box/training_box.py +4 -12
  21. agentscope_runtime/sandbox/build.py +37 -17
  22. agentscope_runtime/sandbox/client/http_client.py +42 -10
  23. agentscope_runtime/sandbox/client/training_client.py +0 -1
  24. agentscope_runtime/sandbox/constant.py +26 -0
  25. agentscope_runtime/sandbox/custom/custom_sandbox.py +5 -5
  26. agentscope_runtime/sandbox/custom/example.py +2 -2
  27. agentscope_runtime/sandbox/manager/collections/in_memory_mapping.py +4 -2
  28. agentscope_runtime/sandbox/manager/collections/redis_mapping.py +25 -9
  29. agentscope_runtime/sandbox/manager/container_clients/__init__.py +0 -10
  30. agentscope_runtime/sandbox/manager/container_clients/agentrun_client.py +1096 -0
  31. agentscope_runtime/sandbox/manager/container_clients/docker_client.py +25 -201
  32. agentscope_runtime/sandbox/manager/container_clients/kubernetes_client.py +1 -3
  33. agentscope_runtime/sandbox/manager/sandbox_manager.py +40 -13
  34. agentscope_runtime/sandbox/manager/server/app.py +27 -0
  35. agentscope_runtime/sandbox/manager/server/config.py +30 -2
  36. agentscope_runtime/sandbox/model/container.py +1 -1
  37. agentscope_runtime/sandbox/model/manager_config.py +93 -5
  38. agentscope_runtime/sandbox/utils.py +97 -0
  39. agentscope_runtime/version.py +1 -1
  40. {agentscope_runtime-0.1.3.dist-info → agentscope_runtime-0.1.5.dist-info}/METADATA +56 -57
  41. {agentscope_runtime-0.1.3.dist-info → agentscope_runtime-0.1.5.dist-info}/RECORD +45 -40
  42. agentscope_runtime/engine/agents/llm_agent.py +0 -51
  43. agentscope_runtime/engine/llms/__init__.py +0 -3
  44. agentscope_runtime/engine/llms/base_llm.py +0 -60
  45. agentscope_runtime/engine/llms/qwen_llm.py +0 -47
  46. {agentscope_runtime-0.1.3.dist-info → agentscope_runtime-0.1.5.dist-info}/WHEEL +0 -0
  47. {agentscope_runtime-0.1.3.dist-info → agentscope_runtime-0.1.5.dist-info}/entry_points.txt +0 -0
  48. {agentscope_runtime-0.1.3.dist-info → agentscope_runtime-0.1.5.dist-info}/licenses/LICENSE +0 -0
  49. {agentscope_runtime-0.1.3.dist-info → agentscope_runtime-0.1.5.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,304 @@
1
+ # -*- coding: utf-8 -*-
2
+ # pylint: disable=redefined-outer-name
3
+ import asyncio
4
+ import copy
5
+ from enum import Enum
6
+ from typing import Any, Dict, List, Optional
7
+
8
+ try:
9
+ import tablestore
10
+ from langchain_community.embeddings import DashScopeEmbeddings
11
+ from langchain_core.embeddings import Embeddings
12
+ from tablestore import AsyncOTSClient as AsyncTablestoreClient
13
+ from tablestore import VectorMetricType
14
+ from tablestore_for_agent_memory.base.filter import Filters
15
+ from tablestore_for_agent_memory.knowledge.async_knowledge_store import (
16
+ AsyncKnowledgeStore,
17
+ )
18
+ except ImportError as e:
19
+ raise ImportError(
20
+ "aliyun_tablestore is not available. "
21
+ "Please run pip install agentscope-runtime[aliyun_tablestore_ext]",
22
+ ) from e
23
+
24
+ from ..schemas.agent_schemas import Message, MessageType
25
+ from .memory_service import MemoryService
26
+ from .utils.tablestore_service_utils import (
27
+ convert_messages_to_tablestore_documents,
28
+ convert_tablestore_document_to_message,
29
+ get_message_metadata_names,
30
+ tablestore_log,
31
+ )
32
+
33
+
34
+ class SearchStrategy(Enum):
35
+ FULL_TEXT = "full_text"
36
+ VECTOR = "vector"
37
+
38
+
39
+ class TablestoreMemoryService(MemoryService):
40
+ """
41
+ A Tablestore-based implementation of the memory service.
42
+ based on tablestore_for_agent_memory
43
+ (https://github.com/aliyun/
44
+ alibabacloud-tablestore-for-agent-memory/blob/main/python/docs/knowledge_store_tutorial.ipynb).
45
+ """
46
+
47
+ _SEARCH_INDEX_NAME = "agentscope_runtime_knowledge_search_index_name"
48
+ _DEFAULT_SESSION_ID = "default"
49
+
50
+ def __init__(
51
+ self,
52
+ tablestore_client: AsyncTablestoreClient,
53
+ search_strategy: SearchStrategy = SearchStrategy.FULL_TEXT,
54
+ embedding_model: Optional[Embeddings] = DashScopeEmbeddings(),
55
+ vector_dimension: int = 1536,
56
+ table_name: Optional[str] = "agentscope_runtime_memory",
57
+ search_index_schema: Optional[List[tablestore.FieldSchema]] = (
58
+ tablestore.FieldSchema("user_id", tablestore.FieldType.KEYWORD),
59
+ tablestore.FieldSchema("session_id", tablestore.FieldType.KEYWORD),
60
+ ),
61
+ text_field: Optional[str] = "text",
62
+ embedding_field: Optional[str] = "embedding",
63
+ vector_metric_type: VectorMetricType = VectorMetricType.VM_COSINE,
64
+ **kwargs: Any,
65
+ ):
66
+ self._search_strategy = search_strategy
67
+ self._embedding_model = (
68
+ embedding_model # the parameter is None, don't store vector.
69
+ )
70
+
71
+ if (
72
+ self._search_strategy == SearchStrategy.VECTOR
73
+ and self._embedding_model is None
74
+ ):
75
+ raise ValueError(
76
+ "Embedding model is required when search strategy is VECTOR.",
77
+ )
78
+
79
+ self._tablestore_client = tablestore_client
80
+ self._vector_dimension = vector_dimension
81
+ self._table_name = table_name
82
+ self._search_index_schema = (
83
+ list(search_index_schema)
84
+ if search_index_schema is not None
85
+ else None
86
+ )
87
+ self._text_field = text_field
88
+ self._embedding_field = embedding_field
89
+ self._vector_metric_type = vector_metric_type
90
+ self._knowledge_store: Optional[AsyncKnowledgeStore] = None
91
+ self._knowledge_store_init_parameter_kwargs = kwargs
92
+
93
+ async def _init_knowledge_store(self) -> None:
94
+ self._knowledge_store = AsyncKnowledgeStore(
95
+ tablestore_client=self._tablestore_client,
96
+ vector_dimension=self._vector_dimension,
97
+ enable_multi_tenant=False,
98
+ # enable multi tenant will make user be confused,
99
+ # we unify the usage of session id and user id,
100
+ # and allow users to configure the index themselves.
101
+ table_name=self._table_name,
102
+ search_index_name=TablestoreMemoryService._SEARCH_INDEX_NAME,
103
+ search_index_schema=copy.deepcopy(self._search_index_schema),
104
+ text_field=self._text_field,
105
+ embedding_field=self._embedding_field,
106
+ vector_metric_type=self._vector_metric_type,
107
+ **self._knowledge_store_init_parameter_kwargs,
108
+ )
109
+
110
+ await self._knowledge_store.init_table()
111
+
112
+ async def start(self) -> None:
113
+ """Start the tablestore service"""
114
+ if self._knowledge_store:
115
+ return
116
+ await self._init_knowledge_store()
117
+
118
+ async def stop(self) -> None:
119
+ """Close the tablestore service"""
120
+ if self._knowledge_store is None:
121
+ return
122
+ knowledge_store = self._knowledge_store
123
+ self._knowledge_store = None
124
+ await knowledge_store.close()
125
+
126
+ async def health(self) -> bool:
127
+ """Checks the health of the service."""
128
+ if self._knowledge_store is None:
129
+ tablestore_log("Tablestore memory service is not started.")
130
+ return False
131
+
132
+ try:
133
+ async for _ in await self._knowledge_store.get_all_documents():
134
+ return True
135
+ return True
136
+ except Exception as e:
137
+ tablestore_log(
138
+ f"Tablestore memory service "
139
+ f"cannot access Tablestore, error: {str(e)}.",
140
+ )
141
+ return False
142
+
143
+ async def add_memory(
144
+ self,
145
+ user_id: str,
146
+ messages: list,
147
+ session_id: Optional[str] = None,
148
+ ) -> None:
149
+ if not session_id:
150
+ session_id = TablestoreMemoryService._DEFAULT_SESSION_ID
151
+
152
+ if not messages:
153
+ return
154
+
155
+ tablestore_documents = convert_messages_to_tablestore_documents(
156
+ messages,
157
+ user_id,
158
+ session_id,
159
+ self._embedding_model,
160
+ )
161
+
162
+ put_tasks = [
163
+ self._knowledge_store.put_document(tablestore_document)
164
+ for tablestore_document in tablestore_documents
165
+ ]
166
+ await asyncio.gather(*put_tasks)
167
+
168
+ @staticmethod
169
+ async def get_query_text(message: Message) -> str:
170
+ if not message or message.type != MessageType.MESSAGE:
171
+ return ""
172
+
173
+ for content in message.content:
174
+ if content.type == "text":
175
+ return content.text
176
+
177
+ return ""
178
+
179
+ async def search_memory(
180
+ self,
181
+ user_id: str,
182
+ messages: list,
183
+ filters: Optional[Dict[str, Any]] = None,
184
+ ) -> list:
185
+ if (
186
+ not messages
187
+ or not isinstance(messages, list)
188
+ or len(messages) == 0
189
+ ):
190
+ return []
191
+
192
+ query = await TablestoreMemoryService.get_query_text(messages[-1])
193
+ if not query:
194
+ return []
195
+
196
+ top_k = 100
197
+ if (
198
+ filters
199
+ and "top_k" in filters
200
+ and isinstance(filters["top_k"], int)
201
+ ):
202
+ top_k = filters["top_k"]
203
+
204
+ if self._search_strategy == SearchStrategy.FULL_TEXT:
205
+ matched_messages = [
206
+ convert_tablestore_document_to_message(hit.document)
207
+ for hit in (
208
+ await self._knowledge_store.full_text_search(
209
+ query=query,
210
+ metadata_filter=Filters.eq("user_id", user_id),
211
+ limit=top_k,
212
+ meta_data_to_get=get_message_metadata_names(),
213
+ )
214
+ ).hits
215
+ ]
216
+ elif self._search_strategy == SearchStrategy.VECTOR:
217
+ matched_messages = [
218
+ convert_tablestore_document_to_message(hit.document)
219
+ for hit in (
220
+ await self._knowledge_store.vector_search(
221
+ query_vector=self._embedding_model.embed_query(query),
222
+ metadata_filter=Filters.eq("user_id", user_id),
223
+ top_k=top_k,
224
+ meta_data_to_get=get_message_metadata_names(),
225
+ )
226
+ ).hits
227
+ ]
228
+ else:
229
+ raise ValueError(
230
+ f"Unsupported search strategy: {self._search_strategy}",
231
+ )
232
+
233
+ return matched_messages
234
+
235
+ async def list_memory(
236
+ self,
237
+ user_id: str,
238
+ filters: Optional[Dict[str, Any]] = None,
239
+ ) -> list:
240
+ page_num = filters.get("page_num", 1) if filters else 1
241
+ page_size = filters.get("page_size", 10) if filters else 10
242
+
243
+ if page_num < 1 or page_size < 1:
244
+ raise ValueError("page_num and page_size must be greater than 0.")
245
+
246
+ next_token = None
247
+ for _ in range(page_num - 1):
248
+ next_token = (
249
+ await self._knowledge_store.search_documents(
250
+ metadata_filter=Filters.eq("user_id", user_id),
251
+ limit=page_size,
252
+ next_token=next_token,
253
+ )
254
+ ).next_token
255
+ if not next_token:
256
+ tablestore_log(
257
+ "Page number exceeds the total number of pages, "
258
+ "return empty list.",
259
+ )
260
+ return []
261
+
262
+ messages = [
263
+ convert_tablestore_document_to_message(hit.document)
264
+ for hit in (
265
+ await self._knowledge_store.search_documents(
266
+ metadata_filter=Filters.eq("user_id", user_id),
267
+ limit=page_size,
268
+ next_token=next_token,
269
+ meta_data_to_get=get_message_metadata_names(),
270
+ )
271
+ ).hits
272
+ ]
273
+
274
+ return messages
275
+
276
+ async def delete_memory(
277
+ self,
278
+ user_id: str,
279
+ session_id: Optional[str] = None,
280
+ ) -> None:
281
+ delete_tablestore_documents = [
282
+ hit.document
283
+ for hit in (
284
+ await self._knowledge_store.search_documents(
285
+ metadata_filter=(
286
+ Filters.eq("user_id", user_id)
287
+ if not session_id
288
+ else Filters.logical_and(
289
+ [
290
+ Filters.eq("user_id", user_id),
291
+ Filters.eq("session_id", session_id),
292
+ ],
293
+ )
294
+ ),
295
+ )
296
+ ).hits
297
+ ]
298
+ delete_tasks = [
299
+ self._knowledge_store.delete_document(
300
+ tablestore_document.document_id,
301
+ )
302
+ for tablestore_document in delete_tablestore_documents
303
+ ]
304
+ await asyncio.gather(*delete_tasks)
@@ -0,0 +1,143 @@
1
+ # -*- coding: utf-8 -*-
2
+ # pylint: disable=redefined-outer-name
3
+ import asyncio
4
+ import uuid
5
+ from typing import Any, List, Optional, Union
6
+
7
+ try:
8
+ from langchain_community.embeddings import DashScopeEmbeddings
9
+ from langchain_core.documents import Document
10
+ from langchain_core.embeddings import Embeddings
11
+ from tablestore import AsyncOTSClient as AsyncTablestoreClient
12
+ from tablestore import VectorMetricType
13
+ from tablestore_for_agent_memory.base.base_knowledge_store import (
14
+ Document as TablestoreDocument,
15
+ )
16
+ from tablestore_for_agent_memory.knowledge.async_knowledge_store import (
17
+ AsyncKnowledgeStore,
18
+ )
19
+ except ImportError as e:
20
+ raise ImportError(
21
+ "aliyun_tablestore is not available. "
22
+ "Please run pip install agentscope-runtime[aliyun_tablestore_ext]",
23
+ ) from e
24
+
25
+ from .rag_service import RAGService
26
+ from .utils.tablestore_service_utils import tablestore_log
27
+
28
+
29
+ class TablestoreRAGService(RAGService):
30
+ """
31
+ RAG Service using Tablestore(aliyun tablestore)
32
+ based on tablestore_for_agent_memory
33
+ (https://github.com/aliyun/
34
+ alibabacloud-tablestore-for-agent-memory/blob/main/python/docs/knowledge_store_tutorial.ipynb).
35
+ """
36
+
37
+ _SEARCH_INDEX_NAME = "agentscope_runtime_knowledge_search_index_name"
38
+ _DEFAULT_SESSION_ID = "default"
39
+
40
+ def __init__(
41
+ self,
42
+ tablestore_client: AsyncTablestoreClient,
43
+ embedding_model: Optional[Embeddings] = None,
44
+ vector_dimension: int = 1536,
45
+ table_name: Optional[str] = "agentscope_runtime_rag",
46
+ text_field: Optional[str] = "text",
47
+ embedding_field: Optional[str] = "embedding",
48
+ vector_metric_type: VectorMetricType = VectorMetricType.VM_COSINE,
49
+ **kwargs: Any,
50
+ ):
51
+ self._embedding_model = (
52
+ embedding_model if embedding_model else DashScopeEmbeddings()
53
+ )
54
+
55
+ self._tablestore_client = tablestore_client
56
+ self._vector_dimension = vector_dimension
57
+ self._table_name = table_name
58
+ self._text_field = text_field
59
+ self._embedding_field = embedding_field
60
+ self._vector_metric_type = vector_metric_type
61
+ self._knowledge_store: Optional[AsyncKnowledgeStore] = None
62
+ self._knowledge_store_init_parameter_kwargs = kwargs
63
+
64
+ async def _init_knowledge_store(self) -> None:
65
+ self._knowledge_store = AsyncKnowledgeStore(
66
+ tablestore_client=self._tablestore_client,
67
+ vector_dimension=self._vector_dimension,
68
+ enable_multi_tenant=False,
69
+ table_name=self._table_name,
70
+ search_index_name=TablestoreRAGService._SEARCH_INDEX_NAME,
71
+ text_field=self._text_field,
72
+ embedding_field=self._embedding_field,
73
+ vector_metric_type=self._vector_metric_type,
74
+ **self._knowledge_store_init_parameter_kwargs,
75
+ )
76
+
77
+ await self._knowledge_store.init_table()
78
+
79
+ async def start(self) -> None:
80
+ """Start the tablestore service"""
81
+ if self._knowledge_store:
82
+ return
83
+ await self._init_knowledge_store()
84
+
85
+ async def stop(self) -> None:
86
+ """Close the tablestore service"""
87
+ if self._knowledge_store is None:
88
+ return
89
+ knowledge_store = self._knowledge_store
90
+ self._knowledge_store = None
91
+ await knowledge_store.close()
92
+
93
+ async def health(self) -> bool:
94
+ """Checks the health of the service."""
95
+ if self._knowledge_store is None:
96
+ tablestore_log("Tablestore rag service is not started.")
97
+ return False
98
+
99
+ try:
100
+ async for _ in await self._knowledge_store.get_all_documents():
101
+ return True
102
+ return True
103
+ except Exception as e:
104
+ tablestore_log(
105
+ f"Tablestore rag service "
106
+ f"cannot access Tablestore, error: {str(e)}.",
107
+ )
108
+ return False
109
+
110
+ async def add_docs(self, docs: Union[Document, List[Document]]):
111
+ if not isinstance(docs, List):
112
+ docs = [docs]
113
+
114
+ contents = [doc.page_content for doc in docs]
115
+ # Encode in batches to reduce time consumption.
116
+ embeddings = self._embedding_model.embed_documents(contents)
117
+
118
+ put_tasks = [
119
+ # The conversion logic here is simple,
120
+ # so no separate conversion function is defined.
121
+ self._knowledge_store.put_document(
122
+ document=TablestoreDocument(
123
+ document_id=f"document_{uuid.uuid4()}",
124
+ text=doc.page_content,
125
+ embedding=embedding,
126
+ metadata=doc.metadata,
127
+ ),
128
+ )
129
+ for doc, embedding in zip(docs, embeddings)
130
+ ]
131
+ await asyncio.gather(*put_tasks)
132
+
133
+ async def retrieve(self, query: str, k: int = 1) -> list[str]:
134
+ matched_text = [
135
+ hit.document.text
136
+ for hit in (
137
+ await self._knowledge_store.vector_search(
138
+ query_vector=self._embedding_model.embed_query(query),
139
+ top_k=k,
140
+ )
141
+ ).hits
142
+ ]
143
+ return matched_text