agentscope-runtime 0.1.5b1__py3-none-any.whl → 0.1.6__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/engine/agents/agentscope_agent.py +447 -0
- agentscope_runtime/engine/agents/agno_agent.py +19 -18
- agentscope_runtime/engine/agents/autogen_agent.py +13 -8
- agentscope_runtime/engine/agents/utils.py +53 -0
- agentscope_runtime/engine/deployers/__init__.py +0 -13
- agentscope_runtime/engine/deployers/local_deployer.py +501 -356
- agentscope_runtime/engine/helpers/helper.py +60 -41
- agentscope_runtime/engine/runner.py +11 -36
- agentscope_runtime/engine/schemas/agent_schemas.py +2 -70
- agentscope_runtime/engine/services/sandbox_service.py +62 -70
- agentscope_runtime/engine/services/tablestore_memory_service.py +304 -0
- agentscope_runtime/engine/services/tablestore_rag_service.py +143 -0
- agentscope_runtime/engine/services/tablestore_session_history_service.py +293 -0
- agentscope_runtime/engine/services/utils/tablestore_service_utils.py +352 -0
- agentscope_runtime/sandbox/__init__.py +2 -0
- agentscope_runtime/sandbox/box/base/__init__.py +4 -0
- agentscope_runtime/sandbox/box/base/base_sandbox.py +4 -3
- agentscope_runtime/sandbox/box/browser/__init__.py +4 -0
- agentscope_runtime/sandbox/box/browser/browser_sandbox.py +8 -13
- agentscope_runtime/sandbox/box/dummy/__init__.py +4 -0
- agentscope_runtime/sandbox/box/filesystem/__init__.py +4 -0
- agentscope_runtime/sandbox/box/filesystem/filesystem_sandbox.py +8 -6
- agentscope_runtime/sandbox/box/gui/__init__.py +4 -0
- agentscope_runtime/sandbox/box/gui/gui_sandbox.py +80 -0
- agentscope_runtime/sandbox/box/sandbox.py +5 -2
- agentscope_runtime/sandbox/box/shared/routers/generic.py +20 -1
- agentscope_runtime/sandbox/box/training_box/__init__.py +4 -0
- agentscope_runtime/sandbox/box/training_box/training_box.py +10 -15
- agentscope_runtime/sandbox/build.py +143 -58
- agentscope_runtime/sandbox/client/http_client.py +43 -49
- agentscope_runtime/sandbox/client/training_client.py +0 -1
- agentscope_runtime/sandbox/constant.py +24 -1
- agentscope_runtime/sandbox/custom/custom_sandbox.py +5 -5
- agentscope_runtime/sandbox/custom/example.py +2 -2
- agentscope_runtime/sandbox/enums.py +1 -0
- agentscope_runtime/sandbox/manager/collections/in_memory_mapping.py +11 -6
- agentscope_runtime/sandbox/manager/collections/redis_mapping.py +25 -9
- agentscope_runtime/sandbox/manager/container_clients/__init__.py +0 -10
- agentscope_runtime/sandbox/manager/container_clients/agentrun_client.py +1098 -0
- agentscope_runtime/sandbox/manager/container_clients/docker_client.py +33 -205
- agentscope_runtime/sandbox/manager/container_clients/kubernetes_client.py +8 -555
- agentscope_runtime/sandbox/manager/sandbox_manager.py +187 -88
- agentscope_runtime/sandbox/manager/server/app.py +82 -14
- agentscope_runtime/sandbox/manager/server/config.py +50 -3
- agentscope_runtime/sandbox/model/container.py +6 -23
- agentscope_runtime/sandbox/model/manager_config.py +93 -5
- agentscope_runtime/sandbox/tools/gui/__init__.py +7 -0
- agentscope_runtime/sandbox/tools/gui/tool.py +77 -0
- agentscope_runtime/sandbox/tools/mcp_tool.py +6 -2
- agentscope_runtime/sandbox/utils.py +124 -0
- agentscope_runtime/version.py +1 -1
- {agentscope_runtime-0.1.5b1.dist-info → agentscope_runtime-0.1.6.dist-info}/METADATA +168 -77
- {agentscope_runtime-0.1.5b1.dist-info → agentscope_runtime-0.1.6.dist-info}/RECORD +59 -78
- {agentscope_runtime-0.1.5b1.dist-info → agentscope_runtime-0.1.6.dist-info}/entry_points.txt +0 -1
- agentscope_runtime/engine/agents/agentscope_agent/__init__.py +0 -6
- agentscope_runtime/engine/agents/agentscope_agent/agent.py +0 -401
- agentscope_runtime/engine/agents/agentscope_agent/hooks.py +0 -169
- agentscope_runtime/engine/agents/llm_agent.py +0 -51
- agentscope_runtime/engine/deployers/adapter/responses/response_api_adapter_utils.py +0 -2886
- agentscope_runtime/engine/deployers/adapter/responses/response_api_agent_adapter.py +0 -51
- agentscope_runtime/engine/deployers/adapter/responses/response_api_protocol_adapter.py +0 -314
- agentscope_runtime/engine/deployers/cli_fc_deploy.py +0 -143
- agentscope_runtime/engine/deployers/kubernetes_deployer.py +0 -265
- agentscope_runtime/engine/deployers/modelstudio_deployer.py +0 -626
- agentscope_runtime/engine/deployers/utils/deployment_modes.py +0 -14
- agentscope_runtime/engine/deployers/utils/docker_image_utils/__init__.py +0 -8
- agentscope_runtime/engine/deployers/utils/docker_image_utils/docker_image_builder.py +0 -429
- agentscope_runtime/engine/deployers/utils/docker_image_utils/dockerfile_generator.py +0 -240
- agentscope_runtime/engine/deployers/utils/docker_image_utils/runner_image_factory.py +0 -297
- agentscope_runtime/engine/deployers/utils/package_project_utils.py +0 -932
- agentscope_runtime/engine/deployers/utils/service_utils/__init__.py +0 -9
- agentscope_runtime/engine/deployers/utils/service_utils/fastapi_factory.py +0 -504
- agentscope_runtime/engine/deployers/utils/service_utils/fastapi_templates.py +0 -157
- agentscope_runtime/engine/deployers/utils/service_utils/process_manager.py +0 -268
- agentscope_runtime/engine/deployers/utils/service_utils/service_config.py +0 -75
- agentscope_runtime/engine/deployers/utils/service_utils/service_factory.py +0 -220
- agentscope_runtime/engine/deployers/utils/wheel_packager.py +0 -389
- agentscope_runtime/engine/helpers/agent_api_builder.py +0 -651
- agentscope_runtime/engine/llms/__init__.py +0 -3
- agentscope_runtime/engine/llms/base_llm.py +0 -60
- agentscope_runtime/engine/llms/qwen_llm.py +0 -47
- agentscope_runtime/engine/schemas/embedding.py +0 -37
- agentscope_runtime/engine/schemas/modelstudio_llm.py +0 -310
- agentscope_runtime/engine/schemas/oai_llm.py +0 -538
- agentscope_runtime/engine/schemas/realtime.py +0 -254
- /agentscope_runtime/engine/{deployers/adapter/responses → services/utils}/__init__.py +0 -0
- /agentscope_runtime/{engine/deployers/utils → sandbox/box/gui/box}/__init__.py +0 -0
- {agentscope_runtime-0.1.5b1.dist-info → agentscope_runtime-0.1.6.dist-info}/WHEEL +0 -0
- {agentscope_runtime-0.1.5b1.dist-info → agentscope_runtime-0.1.6.dist-info}/licenses/LICENSE +0 -0
- {agentscope_runtime-0.1.5b1.dist-info → agentscope_runtime-0.1.6.dist-info}/top_level.txt +0 -0
|
@@ -1,651 +0,0 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
"""
|
|
3
|
-
Agent Protocol Data Generator
|
|
4
|
-
|
|
5
|
-
Provides layered Builder pattern tools to generate streaming response data
|
|
6
|
-
that conforms to types/agent definitions
|
|
7
|
-
"""
|
|
8
|
-
|
|
9
|
-
import time
|
|
10
|
-
from typing import Any, Dict, Generator, List, Optional
|
|
11
|
-
from uuid import uuid4
|
|
12
|
-
|
|
13
|
-
from agentscope_runtime.engine.schemas.agent_schemas import (
|
|
14
|
-
AgentResponse,
|
|
15
|
-
AudioContent,
|
|
16
|
-
Content,
|
|
17
|
-
ContentType,
|
|
18
|
-
DataContent,
|
|
19
|
-
FileContent,
|
|
20
|
-
ImageContent,
|
|
21
|
-
Message,
|
|
22
|
-
RefusalContent,
|
|
23
|
-
Role,
|
|
24
|
-
TextContent,
|
|
25
|
-
)
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
class ContentBuilder:
|
|
29
|
-
"""
|
|
30
|
-
Content Builder
|
|
31
|
-
|
|
32
|
-
Responsible for building and managing individual Content objects,
|
|
33
|
-
supporting Text, Image, and Data content types
|
|
34
|
-
"""
|
|
35
|
-
|
|
36
|
-
def __init__(
|
|
37
|
-
self,
|
|
38
|
-
message_builder: "MessageBuilder",
|
|
39
|
-
content_type: str = ContentType.TEXT,
|
|
40
|
-
index: int = 0,
|
|
41
|
-
):
|
|
42
|
-
"""
|
|
43
|
-
Initialize Content Builder
|
|
44
|
-
|
|
45
|
-
Args:
|
|
46
|
-
message_builder: Associated MessageBuilder object
|
|
47
|
-
content_type: Content type ('text', 'image', 'data')
|
|
48
|
-
index: Content index, defaults to 0
|
|
49
|
-
"""
|
|
50
|
-
self.message_builder = message_builder
|
|
51
|
-
self.content_type = content_type
|
|
52
|
-
self.index = index
|
|
53
|
-
|
|
54
|
-
# Initialize corresponding data structures and content objects
|
|
55
|
-
# based on Content type
|
|
56
|
-
if content_type == ContentType.TEXT:
|
|
57
|
-
self.text_tokens: List[str] = []
|
|
58
|
-
self.content = TextContent(
|
|
59
|
-
type=self.content_type,
|
|
60
|
-
index=self.index,
|
|
61
|
-
msg_id=self.message_builder.message.id,
|
|
62
|
-
)
|
|
63
|
-
elif content_type == ContentType.IMAGE:
|
|
64
|
-
self.content = ImageContent(
|
|
65
|
-
type=self.content_type,
|
|
66
|
-
index=self.index,
|
|
67
|
-
msg_id=self.message_builder.message.id,
|
|
68
|
-
)
|
|
69
|
-
elif content_type == ContentType.DATA:
|
|
70
|
-
self.data_deltas: List[Dict[str, Any]] = []
|
|
71
|
-
self.content = DataContent(
|
|
72
|
-
type=self.content_type,
|
|
73
|
-
index=self.index,
|
|
74
|
-
msg_id=self.message_builder.message.id,
|
|
75
|
-
)
|
|
76
|
-
elif content_type == ContentType.REFUSAL:
|
|
77
|
-
self.content = RefusalContent(
|
|
78
|
-
type=self.content_type,
|
|
79
|
-
index=self.index,
|
|
80
|
-
msg_id=self.message_builder.message.id,
|
|
81
|
-
)
|
|
82
|
-
elif content_type == ContentType.FILE:
|
|
83
|
-
self.content = FileContent(
|
|
84
|
-
type=self.content_type,
|
|
85
|
-
index=self.index,
|
|
86
|
-
msg_id=self.message_builder.message.id,
|
|
87
|
-
)
|
|
88
|
-
elif content_type == ContentType.AUDIO:
|
|
89
|
-
self.content = AudioContent(
|
|
90
|
-
type=self.content_type,
|
|
91
|
-
index=self.index,
|
|
92
|
-
msg_id=self.message_builder.message.id,
|
|
93
|
-
)
|
|
94
|
-
else:
|
|
95
|
-
raise ValueError(f"Unsupported content type: {content_type}")
|
|
96
|
-
|
|
97
|
-
def add_text_delta(self, text: str) -> TextContent:
|
|
98
|
-
"""
|
|
99
|
-
Add text delta (only applicable to text type)
|
|
100
|
-
|
|
101
|
-
Args:
|
|
102
|
-
text: Text fragment
|
|
103
|
-
|
|
104
|
-
Returns:
|
|
105
|
-
Delta content object
|
|
106
|
-
"""
|
|
107
|
-
if self.content_type != ContentType.TEXT:
|
|
108
|
-
raise ValueError("add_text_delta only supported for text content")
|
|
109
|
-
|
|
110
|
-
self.text_tokens.append(text)
|
|
111
|
-
|
|
112
|
-
# Create delta content
|
|
113
|
-
delta_content = TextContent(
|
|
114
|
-
type=self.content_type,
|
|
115
|
-
index=self.index,
|
|
116
|
-
delta=True,
|
|
117
|
-
msg_id=self.message_builder.message.id,
|
|
118
|
-
text=text,
|
|
119
|
-
).in_progress()
|
|
120
|
-
|
|
121
|
-
return delta_content
|
|
122
|
-
|
|
123
|
-
def set_text(self, text: str) -> TextContent:
|
|
124
|
-
"""
|
|
125
|
-
Set complete text content (only applicable to text type)
|
|
126
|
-
|
|
127
|
-
Args:
|
|
128
|
-
text: Complete text content
|
|
129
|
-
|
|
130
|
-
Returns:
|
|
131
|
-
Content object
|
|
132
|
-
"""
|
|
133
|
-
if self.content_type != ContentType.TEXT:
|
|
134
|
-
raise ValueError("set_text only supported for text content")
|
|
135
|
-
|
|
136
|
-
self.content.text = text
|
|
137
|
-
self.content.in_progress()
|
|
138
|
-
return self.content
|
|
139
|
-
|
|
140
|
-
def set_refusal(self, text: str) -> RefusalContent:
|
|
141
|
-
"""
|
|
142
|
-
Set complete refusal content (only applicable to refusal type)
|
|
143
|
-
|
|
144
|
-
Args:
|
|
145
|
-
text: Complete refusal content
|
|
146
|
-
|
|
147
|
-
Returns:
|
|
148
|
-
Content object
|
|
149
|
-
"""
|
|
150
|
-
if self.content_type != ContentType.REFUSAL:
|
|
151
|
-
raise ValueError("set_refusal only supported for refusal content")
|
|
152
|
-
|
|
153
|
-
self.content.refusal = text
|
|
154
|
-
self.content.in_progress()
|
|
155
|
-
return self.content
|
|
156
|
-
|
|
157
|
-
def set_image_url(self, image_url: str) -> ImageContent:
|
|
158
|
-
"""
|
|
159
|
-
Set image URL (only applicable to image type)
|
|
160
|
-
|
|
161
|
-
Args:
|
|
162
|
-
image_url: Image URL
|
|
163
|
-
|
|
164
|
-
Returns:
|
|
165
|
-
Content object
|
|
166
|
-
"""
|
|
167
|
-
if self.content_type != ContentType.IMAGE:
|
|
168
|
-
raise ValueError("set_image_url only supported for image content")
|
|
169
|
-
|
|
170
|
-
self.content.image_url = image_url
|
|
171
|
-
self.content.in_progress()
|
|
172
|
-
return self.content
|
|
173
|
-
|
|
174
|
-
def set_data(self, data: Dict[str, Any]) -> DataContent:
|
|
175
|
-
"""
|
|
176
|
-
Set data content (only applicable to data type)
|
|
177
|
-
|
|
178
|
-
Args:
|
|
179
|
-
data: Data dictionary
|
|
180
|
-
|
|
181
|
-
Returns:
|
|
182
|
-
Content object
|
|
183
|
-
"""
|
|
184
|
-
if self.content_type != ContentType.DATA:
|
|
185
|
-
raise ValueError("set_data only supported for data content")
|
|
186
|
-
|
|
187
|
-
self.content.data = data
|
|
188
|
-
self.content.in_progress()
|
|
189
|
-
return self.content
|
|
190
|
-
|
|
191
|
-
def update_data(self, key: str, value: Any) -> DataContent:
|
|
192
|
-
"""
|
|
193
|
-
Update specific fields of data content (only applicable to data type)
|
|
194
|
-
|
|
195
|
-
Args:
|
|
196
|
-
key: Data key
|
|
197
|
-
value: Data value
|
|
198
|
-
|
|
199
|
-
Returns:
|
|
200
|
-
Content object
|
|
201
|
-
"""
|
|
202
|
-
if self.content_type != ContentType.DATA:
|
|
203
|
-
raise ValueError("update_data only supported for data content")
|
|
204
|
-
|
|
205
|
-
if self.content.data is None:
|
|
206
|
-
self.content.data = {}
|
|
207
|
-
self.content.data[key] = value
|
|
208
|
-
self.content.in_progress()
|
|
209
|
-
return self.content
|
|
210
|
-
|
|
211
|
-
def add_data_delta(self, delta_data: Dict[str, Any]) -> DataContent:
|
|
212
|
-
"""
|
|
213
|
-
Add data delta (only applicable to data type)
|
|
214
|
-
|
|
215
|
-
Args:
|
|
216
|
-
delta_data: Delta data dictionary
|
|
217
|
-
|
|
218
|
-
Returns:
|
|
219
|
-
Delta content object
|
|
220
|
-
"""
|
|
221
|
-
if self.content_type != ContentType.DATA:
|
|
222
|
-
raise ValueError("add_data_delta only supported for data content")
|
|
223
|
-
|
|
224
|
-
self.data_deltas.append(delta_data)
|
|
225
|
-
|
|
226
|
-
# Create delta content object
|
|
227
|
-
delta_content = DataContent(
|
|
228
|
-
type=self.content_type,
|
|
229
|
-
index=self.index,
|
|
230
|
-
delta=True,
|
|
231
|
-
msg_id=self.message_builder.message.id,
|
|
232
|
-
data=delta_data,
|
|
233
|
-
).in_progress()
|
|
234
|
-
|
|
235
|
-
return delta_content
|
|
236
|
-
|
|
237
|
-
def _merge_data_incrementally(
|
|
238
|
-
self,
|
|
239
|
-
base_data: Dict[str, Any],
|
|
240
|
-
delta_data: Dict[str, Any],
|
|
241
|
-
) -> Dict[str, Any]:
|
|
242
|
-
"""
|
|
243
|
-
Intelligently merge data deltas
|
|
244
|
-
|
|
245
|
-
Args:
|
|
246
|
-
base_data: Base data
|
|
247
|
-
delta_data: Delta data
|
|
248
|
-
|
|
249
|
-
Returns:
|
|
250
|
-
Merged data
|
|
251
|
-
"""
|
|
252
|
-
result = base_data.copy() if base_data else {}
|
|
253
|
-
|
|
254
|
-
for key, delta_value in delta_data.items():
|
|
255
|
-
if key not in result:
|
|
256
|
-
# New key, add directly
|
|
257
|
-
result[key] = delta_value
|
|
258
|
-
else:
|
|
259
|
-
base_value = result[key]
|
|
260
|
-
# Perform delta merge based on data type
|
|
261
|
-
if isinstance(base_value, str) and isinstance(
|
|
262
|
-
delta_value,
|
|
263
|
-
str,
|
|
264
|
-
):
|
|
265
|
-
# String concatenation
|
|
266
|
-
result[key] = base_value + delta_value
|
|
267
|
-
elif (
|
|
268
|
-
isinstance(base_value, (int, float))
|
|
269
|
-
and isinstance(delta_value, (int, float))
|
|
270
|
-
and not isinstance(base_value, bool)
|
|
271
|
-
and not isinstance(delta_value, bool)
|
|
272
|
-
):
|
|
273
|
-
# Numeric accumulation (excluding bool type,
|
|
274
|
-
# as bool is a subclass of int)
|
|
275
|
-
result[key] = base_value + delta_value
|
|
276
|
-
elif isinstance(base_value, list) and isinstance(
|
|
277
|
-
delta_value,
|
|
278
|
-
list,
|
|
279
|
-
):
|
|
280
|
-
# List merging
|
|
281
|
-
result[key] = base_value + delta_value
|
|
282
|
-
elif isinstance(base_value, dict) and isinstance(
|
|
283
|
-
delta_value,
|
|
284
|
-
dict,
|
|
285
|
-
):
|
|
286
|
-
# Dictionary recursive merging
|
|
287
|
-
result[key] = self._merge_data_incrementally(
|
|
288
|
-
base_value,
|
|
289
|
-
delta_value,
|
|
290
|
-
)
|
|
291
|
-
else:
|
|
292
|
-
# Other cases directly replace (including bool,
|
|
293
|
-
# different types, etc.)
|
|
294
|
-
result[key] = delta_value
|
|
295
|
-
|
|
296
|
-
return result
|
|
297
|
-
|
|
298
|
-
def add_delta(self, text: str) -> TextContent:
|
|
299
|
-
"""
|
|
300
|
-
Add text delta (backward compatibility method)
|
|
301
|
-
|
|
302
|
-
Args:
|
|
303
|
-
text: Text fragment
|
|
304
|
-
|
|
305
|
-
Returns:
|
|
306
|
-
Delta content object
|
|
307
|
-
"""
|
|
308
|
-
return self.add_text_delta(text)
|
|
309
|
-
|
|
310
|
-
def complete(self) -> Message:
|
|
311
|
-
"""
|
|
312
|
-
Complete content building
|
|
313
|
-
|
|
314
|
-
Returns:
|
|
315
|
-
Dictionary representation of complete Content object
|
|
316
|
-
"""
|
|
317
|
-
if self.content_type == ContentType.TEXT:
|
|
318
|
-
# For text content, merge set text and tokens
|
|
319
|
-
if hasattr(self, "text_tokens") and self.text_tokens:
|
|
320
|
-
# Get existing text, if none then empty string
|
|
321
|
-
existing_text = self.content.text or ""
|
|
322
|
-
token_text = "".join(self.text_tokens)
|
|
323
|
-
self.content.text = existing_text + token_text
|
|
324
|
-
self.content.delta = False
|
|
325
|
-
elif self.content_type == ContentType.DATA:
|
|
326
|
-
# For data content, merge set data and delta data
|
|
327
|
-
if hasattr(self, "data_deltas") and self.data_deltas:
|
|
328
|
-
# Get existing data, if none then empty dictionary
|
|
329
|
-
existing_data = self.content.data or {}
|
|
330
|
-
|
|
331
|
-
# Gradually merge all delta data
|
|
332
|
-
final_data = existing_data
|
|
333
|
-
for delta_data in self.data_deltas:
|
|
334
|
-
final_data = self._merge_data_incrementally(
|
|
335
|
-
final_data,
|
|
336
|
-
delta_data,
|
|
337
|
-
)
|
|
338
|
-
|
|
339
|
-
self.content.data = final_data
|
|
340
|
-
self.content.delta = False
|
|
341
|
-
|
|
342
|
-
# Set completion status
|
|
343
|
-
self.content.completed()
|
|
344
|
-
|
|
345
|
-
# Update message content list
|
|
346
|
-
self.message_builder.add_content(self.content)
|
|
347
|
-
|
|
348
|
-
return self.content
|
|
349
|
-
|
|
350
|
-
def get_content_data(self) -> Content:
|
|
351
|
-
"""
|
|
352
|
-
Get dictionary representation of current content
|
|
353
|
-
|
|
354
|
-
Returns:
|
|
355
|
-
Content object
|
|
356
|
-
"""
|
|
357
|
-
return self.content
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
class MessageBuilder:
|
|
361
|
-
"""
|
|
362
|
-
Message Builder
|
|
363
|
-
|
|
364
|
-
Responsible for building and managing individual Message objects
|
|
365
|
-
and updating associated Response
|
|
366
|
-
"""
|
|
367
|
-
|
|
368
|
-
def __init__(
|
|
369
|
-
self,
|
|
370
|
-
response_builder: "ResponseBuilder",
|
|
371
|
-
role: str = Role.ASSISTANT,
|
|
372
|
-
):
|
|
373
|
-
"""
|
|
374
|
-
Initialize Message Builder
|
|
375
|
-
|
|
376
|
-
Args:
|
|
377
|
-
response_builder: Associated ResponseBuilder object
|
|
378
|
-
role: Message role, defaults to assistant
|
|
379
|
-
"""
|
|
380
|
-
self.response_builder = response_builder
|
|
381
|
-
self.role = role
|
|
382
|
-
self.message_id = f"msg_{uuid4()}"
|
|
383
|
-
self.content_builders: List[ContentBuilder] = []
|
|
384
|
-
|
|
385
|
-
# Create message object
|
|
386
|
-
self.message = Message(
|
|
387
|
-
id=self.message_id,
|
|
388
|
-
role=self.role,
|
|
389
|
-
).in_progress()
|
|
390
|
-
|
|
391
|
-
# Immediately add to response output
|
|
392
|
-
self.response_builder.add_message(self.message)
|
|
393
|
-
|
|
394
|
-
def create_content_builder(
|
|
395
|
-
self,
|
|
396
|
-
content_type: str = ContentType.TEXT,
|
|
397
|
-
) -> ContentBuilder:
|
|
398
|
-
"""
|
|
399
|
-
Create Content Builder
|
|
400
|
-
|
|
401
|
-
Args:
|
|
402
|
-
content_type: Content type ('text', 'image', 'data')
|
|
403
|
-
|
|
404
|
-
Returns:
|
|
405
|
-
Newly created ContentBuilder instance
|
|
406
|
-
"""
|
|
407
|
-
index = len(self.content_builders)
|
|
408
|
-
content_builder = ContentBuilder(self, content_type, index)
|
|
409
|
-
self.content_builders.append(content_builder)
|
|
410
|
-
return content_builder
|
|
411
|
-
|
|
412
|
-
def add_content(self, content: Content):
|
|
413
|
-
"""
|
|
414
|
-
Add content to message
|
|
415
|
-
|
|
416
|
-
Args:
|
|
417
|
-
content: Content object
|
|
418
|
-
"""
|
|
419
|
-
if self.message.content is None:
|
|
420
|
-
self.message.content = []
|
|
421
|
-
|
|
422
|
-
# Check if content with same index already exists, replace if exists
|
|
423
|
-
existing_index = None
|
|
424
|
-
for i, existing_content in enumerate(self.message.content):
|
|
425
|
-
if (
|
|
426
|
-
hasattr(existing_content, "index")
|
|
427
|
-
and existing_content.index == content.index
|
|
428
|
-
):
|
|
429
|
-
existing_index = i
|
|
430
|
-
break
|
|
431
|
-
|
|
432
|
-
if existing_index is not None:
|
|
433
|
-
self.message.content[existing_index] = content
|
|
434
|
-
else:
|
|
435
|
-
self.message.content.append(content)
|
|
436
|
-
|
|
437
|
-
# Notify response builder to update
|
|
438
|
-
self.response_builder.update_message(self.message)
|
|
439
|
-
|
|
440
|
-
def get_message_data(self) -> Message:
|
|
441
|
-
"""
|
|
442
|
-
Get dictionary representation of current message
|
|
443
|
-
|
|
444
|
-
Returns:
|
|
445
|
-
Message object
|
|
446
|
-
"""
|
|
447
|
-
return self.message
|
|
448
|
-
|
|
449
|
-
def complete(self) -> Message:
|
|
450
|
-
"""
|
|
451
|
-
Complete message building
|
|
452
|
-
|
|
453
|
-
Returns:
|
|
454
|
-
Dictionary representation of complete message object
|
|
455
|
-
"""
|
|
456
|
-
self.message.completed()
|
|
457
|
-
|
|
458
|
-
# Notify response builder to update
|
|
459
|
-
self.response_builder.update_message(self.message)
|
|
460
|
-
|
|
461
|
-
return self.message
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
class ResponseBuilder:
|
|
465
|
-
"""
|
|
466
|
-
Response Builder
|
|
467
|
-
|
|
468
|
-
Responsible for building and managing AgentResponse objects,
|
|
469
|
-
coordinating MessageBuilder work
|
|
470
|
-
"""
|
|
471
|
-
|
|
472
|
-
def __init__(
|
|
473
|
-
self,
|
|
474
|
-
session_id: Optional[str] = None,
|
|
475
|
-
response_id: Optional[str] = None,
|
|
476
|
-
):
|
|
477
|
-
"""
|
|
478
|
-
Initialize Response Builder
|
|
479
|
-
|
|
480
|
-
Args:
|
|
481
|
-
session_id: Session ID, optional
|
|
482
|
-
"""
|
|
483
|
-
self.session_id = session_id
|
|
484
|
-
self.response_id = response_id
|
|
485
|
-
self.created_at = int(time.time())
|
|
486
|
-
self.message_builders: List[MessageBuilder] = []
|
|
487
|
-
|
|
488
|
-
# Create response object
|
|
489
|
-
self.response = AgentResponse(
|
|
490
|
-
id=self.response_id,
|
|
491
|
-
session_id=self.session_id,
|
|
492
|
-
created_at=self.created_at,
|
|
493
|
-
output=[],
|
|
494
|
-
)
|
|
495
|
-
|
|
496
|
-
def reset(self):
|
|
497
|
-
"""
|
|
498
|
-
Reset builder state, generate new ID and object instances
|
|
499
|
-
"""
|
|
500
|
-
self.response_id = f"response_{uuid4()}"
|
|
501
|
-
self.created_at = int(time.time())
|
|
502
|
-
self.message_builders = []
|
|
503
|
-
|
|
504
|
-
# Recreate response object
|
|
505
|
-
self.response = AgentResponse(
|
|
506
|
-
id=self.response_id,
|
|
507
|
-
session_id=self.session_id,
|
|
508
|
-
created_at=self.created_at,
|
|
509
|
-
output=[],
|
|
510
|
-
)
|
|
511
|
-
|
|
512
|
-
def get_response_data(self) -> AgentResponse:
|
|
513
|
-
"""
|
|
514
|
-
Get dictionary representation of current response
|
|
515
|
-
|
|
516
|
-
Returns:
|
|
517
|
-
Response object
|
|
518
|
-
"""
|
|
519
|
-
return self.response
|
|
520
|
-
|
|
521
|
-
def created(self) -> AgentResponse:
|
|
522
|
-
"""
|
|
523
|
-
Set response status to created
|
|
524
|
-
|
|
525
|
-
Returns:
|
|
526
|
-
Response object
|
|
527
|
-
"""
|
|
528
|
-
self.response.created()
|
|
529
|
-
return self.response
|
|
530
|
-
|
|
531
|
-
def in_progress(self) -> AgentResponse:
|
|
532
|
-
"""
|
|
533
|
-
Set response status to in_progress
|
|
534
|
-
|
|
535
|
-
Returns:
|
|
536
|
-
Response object
|
|
537
|
-
"""
|
|
538
|
-
self.response.in_progress()
|
|
539
|
-
return self.response
|
|
540
|
-
|
|
541
|
-
def completed(self) -> AgentResponse:
|
|
542
|
-
"""
|
|
543
|
-
Set response status to completed
|
|
544
|
-
|
|
545
|
-
Returns:
|
|
546
|
-
Response object
|
|
547
|
-
"""
|
|
548
|
-
self.response.completed()
|
|
549
|
-
return self.response
|
|
550
|
-
|
|
551
|
-
def create_message_builder(
|
|
552
|
-
self,
|
|
553
|
-
role: str = Role.ASSISTANT,
|
|
554
|
-
message_type: str = "message",
|
|
555
|
-
) -> MessageBuilder:
|
|
556
|
-
"""
|
|
557
|
-
Create Message Builder
|
|
558
|
-
|
|
559
|
-
Args:
|
|
560
|
-
role: Message role, defaults to assistant
|
|
561
|
-
message_type: Message type, defaults to message
|
|
562
|
-
|
|
563
|
-
Returns:
|
|
564
|
-
Newly created MessageBuilder instance
|
|
565
|
-
"""
|
|
566
|
-
message_builder = MessageBuilder(self, role)
|
|
567
|
-
|
|
568
|
-
# Set the message type
|
|
569
|
-
message_builder.message.type = message_type
|
|
570
|
-
|
|
571
|
-
self.message_builders.append(message_builder)
|
|
572
|
-
return message_builder
|
|
573
|
-
|
|
574
|
-
def add_message(self, message: Message):
|
|
575
|
-
"""
|
|
576
|
-
Add message to response output list
|
|
577
|
-
|
|
578
|
-
Args:
|
|
579
|
-
message: Message object
|
|
580
|
-
"""
|
|
581
|
-
# Check if message with same ID already exists, replace if exists
|
|
582
|
-
existing_index = None
|
|
583
|
-
for i, existing_message in enumerate(self.response.output):
|
|
584
|
-
if existing_message.id == message.id:
|
|
585
|
-
existing_index = i
|
|
586
|
-
break
|
|
587
|
-
|
|
588
|
-
if existing_index is not None:
|
|
589
|
-
self.response.output[existing_index] = message
|
|
590
|
-
else:
|
|
591
|
-
self.response.output.append(message)
|
|
592
|
-
|
|
593
|
-
def update_message(self, message: Message):
|
|
594
|
-
"""
|
|
595
|
-
Update message in response
|
|
596
|
-
|
|
597
|
-
Args:
|
|
598
|
-
message: Updated Message object
|
|
599
|
-
"""
|
|
600
|
-
for i, existing_message in enumerate(self.response.output):
|
|
601
|
-
if existing_message.id == message.id:
|
|
602
|
-
self.response.output[i] = message
|
|
603
|
-
break
|
|
604
|
-
|
|
605
|
-
def generate_streaming_response(
|
|
606
|
-
self,
|
|
607
|
-
text_tokens: List[str],
|
|
608
|
-
role: str = Role.ASSISTANT,
|
|
609
|
-
) -> Generator[Dict[str, Any], None, None]:
|
|
610
|
-
"""
|
|
611
|
-
Generate complete streaming response sequence
|
|
612
|
-
|
|
613
|
-
Args:
|
|
614
|
-
text_tokens: Text fragment list
|
|
615
|
-
role: Message role, defaults to assistant
|
|
616
|
-
|
|
617
|
-
Yields:
|
|
618
|
-
Dictionary of response objects generated in order
|
|
619
|
-
"""
|
|
620
|
-
# Reset state
|
|
621
|
-
self.reset()
|
|
622
|
-
|
|
623
|
-
# 1. Create response (created)
|
|
624
|
-
yield self.created()
|
|
625
|
-
|
|
626
|
-
# 2. Start response (in_progress)
|
|
627
|
-
yield self.in_progress()
|
|
628
|
-
|
|
629
|
-
# 3. Create Message Builder
|
|
630
|
-
message_builder = self.create_message_builder(role)
|
|
631
|
-
yield message_builder.get_message_data()
|
|
632
|
-
|
|
633
|
-
# 4. Create Content Builder
|
|
634
|
-
content_builder = message_builder.create_content_builder()
|
|
635
|
-
|
|
636
|
-
# 5. Stream output Text fragments
|
|
637
|
-
for token in text_tokens:
|
|
638
|
-
yield content_builder.add_delta(token)
|
|
639
|
-
|
|
640
|
-
# 6. Complete content
|
|
641
|
-
yield content_builder.complete()
|
|
642
|
-
|
|
643
|
-
# 7. Complete message
|
|
644
|
-
yield message_builder.complete()
|
|
645
|
-
|
|
646
|
-
# 8. Complete response
|
|
647
|
-
yield self.completed()
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
# For backward compatibility, provide aliases
|
|
651
|
-
StreamingResponseBuilder = ResponseBuilder
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
from typing import AsyncGenerator
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
class BaseLLM:
|
|
6
|
-
base_url = None
|
|
7
|
-
|
|
8
|
-
def __init__(self, model_name: str, **kwargs):
|
|
9
|
-
self.client = None
|
|
10
|
-
self.async_client = None
|
|
11
|
-
self.model_name = model_name
|
|
12
|
-
self.kwargs = kwargs
|
|
13
|
-
|
|
14
|
-
def generate(self, prompt: str, **kwargs) -> str:
|
|
15
|
-
"""
|
|
16
|
-
Generate a response from the Qwen LLM model.
|
|
17
|
-
|
|
18
|
-
Args:
|
|
19
|
-
prompt (str): The prompt to generate a response for.
|
|
20
|
-
**kwargs: Additional keyword arguments to pass to the model.
|
|
21
|
-
|
|
22
|
-
Returns:
|
|
23
|
-
str: The generated response.
|
|
24
|
-
"""
|
|
25
|
-
response = self.client.chat.completions.create(
|
|
26
|
-
model=self.model_name,
|
|
27
|
-
messages=[
|
|
28
|
-
{"role": "system", "content": "You are a helpful assistant."},
|
|
29
|
-
{"role": "user", "content": prompt},
|
|
30
|
-
],
|
|
31
|
-
**kwargs,
|
|
32
|
-
)
|
|
33
|
-
return response.choices[0].message.content
|
|
34
|
-
|
|
35
|
-
def chat(self, messages, **kwargs) -> str:
|
|
36
|
-
response = self.client.chat.completions.create(
|
|
37
|
-
model=self.model_name,
|
|
38
|
-
messages=messages,
|
|
39
|
-
**kwargs,
|
|
40
|
-
)
|
|
41
|
-
return response.choices[0].message.content
|
|
42
|
-
|
|
43
|
-
async def chat_stream(
|
|
44
|
-
self,
|
|
45
|
-
messages,
|
|
46
|
-
tools=None,
|
|
47
|
-
**kwargs,
|
|
48
|
-
) -> AsyncGenerator[str, None]:
|
|
49
|
-
# call model
|
|
50
|
-
# TODO: use async client
|
|
51
|
-
generator = self.client.chat.completions.create(
|
|
52
|
-
model=self.model_name,
|
|
53
|
-
messages=messages,
|
|
54
|
-
tools=tools,
|
|
55
|
-
stream=True,
|
|
56
|
-
**kwargs,
|
|
57
|
-
)
|
|
58
|
-
|
|
59
|
-
for chunk in generator:
|
|
60
|
-
yield chunk
|