agentscope-runtime 0.1.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.
- agentscope_runtime/__init__.py +4 -0
- agentscope_runtime/engine/__init__.py +9 -0
- agentscope_runtime/engine/agents/__init__.py +2 -0
- agentscope_runtime/engine/agents/agentscope_agent/__init__.py +6 -0
- agentscope_runtime/engine/agents/agentscope_agent/agent.py +342 -0
- agentscope_runtime/engine/agents/agentscope_agent/hooks.py +156 -0
- agentscope_runtime/engine/agents/agno_agent.py +220 -0
- agentscope_runtime/engine/agents/base_agent.py +29 -0
- agentscope_runtime/engine/agents/langgraph_agent.py +59 -0
- agentscope_runtime/engine/agents/llm_agent.py +51 -0
- agentscope_runtime/engine/deployers/__init__.py +3 -0
- agentscope_runtime/engine/deployers/adapter/__init__.py +0 -0
- agentscope_runtime/engine/deployers/adapter/a2a/__init__.py +2 -0
- agentscope_runtime/engine/deployers/adapter/a2a/a2a_adapter_utils.py +425 -0
- agentscope_runtime/engine/deployers/adapter/a2a/a2a_agent_adapter.py +69 -0
- agentscope_runtime/engine/deployers/adapter/a2a/a2a_protocol_adapter.py +60 -0
- agentscope_runtime/engine/deployers/adapter/protocol_adapter.py +24 -0
- agentscope_runtime/engine/deployers/base.py +17 -0
- agentscope_runtime/engine/deployers/local_deployer.py +586 -0
- agentscope_runtime/engine/helpers/helper.py +127 -0
- agentscope_runtime/engine/llms/__init__.py +3 -0
- agentscope_runtime/engine/llms/base_llm.py +60 -0
- agentscope_runtime/engine/llms/qwen_llm.py +47 -0
- agentscope_runtime/engine/misc/__init__.py +0 -0
- agentscope_runtime/engine/runner.py +186 -0
- agentscope_runtime/engine/schemas/__init__.py +0 -0
- agentscope_runtime/engine/schemas/agent_schemas.py +551 -0
- agentscope_runtime/engine/schemas/context.py +54 -0
- agentscope_runtime/engine/services/__init__.py +9 -0
- agentscope_runtime/engine/services/base.py +77 -0
- agentscope_runtime/engine/services/context_manager.py +129 -0
- agentscope_runtime/engine/services/environment_manager.py +50 -0
- agentscope_runtime/engine/services/manager.py +174 -0
- agentscope_runtime/engine/services/memory_service.py +270 -0
- agentscope_runtime/engine/services/sandbox_service.py +198 -0
- agentscope_runtime/engine/services/session_history_service.py +256 -0
- agentscope_runtime/engine/tracing/__init__.py +40 -0
- agentscope_runtime/engine/tracing/base.py +309 -0
- agentscope_runtime/engine/tracing/local_logging_handler.py +356 -0
- agentscope_runtime/engine/tracing/tracing_metric.py +69 -0
- agentscope_runtime/engine/tracing/wrapper.py +321 -0
- agentscope_runtime/sandbox/__init__.py +14 -0
- agentscope_runtime/sandbox/box/__init__.py +0 -0
- agentscope_runtime/sandbox/box/base/__init__.py +0 -0
- agentscope_runtime/sandbox/box/base/base_sandbox.py +37 -0
- agentscope_runtime/sandbox/box/base/box/__init__.py +0 -0
- agentscope_runtime/sandbox/box/browser/__init__.py +0 -0
- agentscope_runtime/sandbox/box/browser/box/__init__.py +0 -0
- agentscope_runtime/sandbox/box/browser/browser_sandbox.py +176 -0
- agentscope_runtime/sandbox/box/dummy/__init__.py +0 -0
- agentscope_runtime/sandbox/box/dummy/dummy_sandbox.py +26 -0
- agentscope_runtime/sandbox/box/filesystem/__init__.py +0 -0
- agentscope_runtime/sandbox/box/filesystem/box/__init__.py +0 -0
- agentscope_runtime/sandbox/box/filesystem/filesystem_sandbox.py +87 -0
- agentscope_runtime/sandbox/box/sandbox.py +115 -0
- agentscope_runtime/sandbox/box/shared/__init__.py +0 -0
- agentscope_runtime/sandbox/box/shared/app.py +44 -0
- agentscope_runtime/sandbox/box/shared/dependencies/__init__.py +5 -0
- agentscope_runtime/sandbox/box/shared/dependencies/deps.py +22 -0
- agentscope_runtime/sandbox/box/shared/routers/__init__.py +12 -0
- agentscope_runtime/sandbox/box/shared/routers/generic.py +173 -0
- agentscope_runtime/sandbox/box/shared/routers/mcp.py +207 -0
- agentscope_runtime/sandbox/box/shared/routers/mcp_utils.py +153 -0
- agentscope_runtime/sandbox/box/shared/routers/runtime_watcher.py +187 -0
- agentscope_runtime/sandbox/box/shared/routers/workspace.py +325 -0
- agentscope_runtime/sandbox/box/training_box/__init__.py +0 -0
- agentscope_runtime/sandbox/box/training_box/base.py +120 -0
- agentscope_runtime/sandbox/box/training_box/env_service.py +752 -0
- agentscope_runtime/sandbox/box/training_box/environments/__init__.py +0 -0
- agentscope_runtime/sandbox/box/training_box/environments/appworld/appworld_env.py +987 -0
- agentscope_runtime/sandbox/box/training_box/registry.py +54 -0
- agentscope_runtime/sandbox/box/training_box/src/trajectory.py +278 -0
- agentscope_runtime/sandbox/box/training_box/training_box.py +219 -0
- agentscope_runtime/sandbox/build.py +213 -0
- agentscope_runtime/sandbox/client/__init__.py +5 -0
- agentscope_runtime/sandbox/client/http_client.py +527 -0
- agentscope_runtime/sandbox/client/training_client.py +265 -0
- agentscope_runtime/sandbox/constant.py +5 -0
- agentscope_runtime/sandbox/custom/__init__.py +16 -0
- agentscope_runtime/sandbox/custom/custom_sandbox.py +40 -0
- agentscope_runtime/sandbox/custom/example.py +37 -0
- agentscope_runtime/sandbox/enums.py +68 -0
- agentscope_runtime/sandbox/manager/__init__.py +4 -0
- agentscope_runtime/sandbox/manager/collections/__init__.py +22 -0
- agentscope_runtime/sandbox/manager/collections/base_mapping.py +20 -0
- agentscope_runtime/sandbox/manager/collections/base_queue.py +25 -0
- agentscope_runtime/sandbox/manager/collections/base_set.py +25 -0
- agentscope_runtime/sandbox/manager/collections/in_memory_mapping.py +22 -0
- agentscope_runtime/sandbox/manager/collections/in_memory_queue.py +28 -0
- agentscope_runtime/sandbox/manager/collections/in_memory_set.py +27 -0
- agentscope_runtime/sandbox/manager/collections/redis_mapping.py +26 -0
- agentscope_runtime/sandbox/manager/collections/redis_queue.py +27 -0
- agentscope_runtime/sandbox/manager/collections/redis_set.py +23 -0
- agentscope_runtime/sandbox/manager/container_clients/__init__.py +8 -0
- agentscope_runtime/sandbox/manager/container_clients/base_client.py +39 -0
- agentscope_runtime/sandbox/manager/container_clients/docker_client.py +170 -0
- agentscope_runtime/sandbox/manager/sandbox_manager.py +694 -0
- agentscope_runtime/sandbox/manager/server/__init__.py +0 -0
- agentscope_runtime/sandbox/manager/server/app.py +194 -0
- agentscope_runtime/sandbox/manager/server/config.py +68 -0
- agentscope_runtime/sandbox/manager/server/models.py +17 -0
- agentscope_runtime/sandbox/manager/storage/__init__.py +10 -0
- agentscope_runtime/sandbox/manager/storage/data_storage.py +16 -0
- agentscope_runtime/sandbox/manager/storage/local_storage.py +44 -0
- agentscope_runtime/sandbox/manager/storage/oss_storage.py +89 -0
- agentscope_runtime/sandbox/manager/utils.py +78 -0
- agentscope_runtime/sandbox/mcp_server.py +192 -0
- agentscope_runtime/sandbox/model/__init__.py +12 -0
- agentscope_runtime/sandbox/model/api.py +16 -0
- agentscope_runtime/sandbox/model/container.py +72 -0
- agentscope_runtime/sandbox/model/manager_config.py +158 -0
- agentscope_runtime/sandbox/registry.py +129 -0
- agentscope_runtime/sandbox/tools/__init__.py +12 -0
- agentscope_runtime/sandbox/tools/base/__init__.py +8 -0
- agentscope_runtime/sandbox/tools/base/tool.py +52 -0
- agentscope_runtime/sandbox/tools/browser/__init__.py +57 -0
- agentscope_runtime/sandbox/tools/browser/tool.py +597 -0
- agentscope_runtime/sandbox/tools/filesystem/__init__.py +32 -0
- agentscope_runtime/sandbox/tools/filesystem/tool.py +319 -0
- agentscope_runtime/sandbox/tools/function_tool.py +321 -0
- agentscope_runtime/sandbox/tools/mcp_tool.py +191 -0
- agentscope_runtime/sandbox/tools/sandbox_tool.py +104 -0
- agentscope_runtime/sandbox/tools/tool.py +123 -0
- agentscope_runtime/sandbox/tools/utils.py +68 -0
- agentscope_runtime/version.py +2 -0
- agentscope_runtime-0.1.0.dist-info/METADATA +327 -0
- agentscope_runtime-0.1.0.dist-info/RECORD +131 -0
- agentscope_runtime-0.1.0.dist-info/WHEEL +5 -0
- agentscope_runtime-0.1.0.dist-info/entry_points.txt +4 -0
- agentscope_runtime-0.1.0.dist-info/licenses/LICENSE +202 -0
- agentscope_runtime-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# pylint: disable=protected-access
|
|
3
|
+
import time
|
|
4
|
+
import traceback
|
|
5
|
+
from abc import ABC, abstractmethod
|
|
6
|
+
from contextlib import contextmanager
|
|
7
|
+
from typing import Any, Dict, List
|
|
8
|
+
|
|
9
|
+
from .tracing_metric import TraceType
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
# Handler Interface
|
|
13
|
+
class TracerHandler(ABC):
|
|
14
|
+
"""Abstract base class for tracer handlers."""
|
|
15
|
+
|
|
16
|
+
@abstractmethod
|
|
17
|
+
def on_start(
|
|
18
|
+
self,
|
|
19
|
+
event_type: TraceType,
|
|
20
|
+
payload: Dict[str, Any],
|
|
21
|
+
**kwargs: Any,
|
|
22
|
+
) -> None:
|
|
23
|
+
"""Handle the start of a trace event.
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
event_type (TraceType): The type of event being traced.
|
|
27
|
+
payload (Dict[str, Any]): The payload data for the event.
|
|
28
|
+
**kwargs (Any): Additional keyword arguments.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
@abstractmethod
|
|
32
|
+
def on_end(
|
|
33
|
+
self,
|
|
34
|
+
event_type: TraceType,
|
|
35
|
+
start_payload: Dict[str, Any],
|
|
36
|
+
end_payload: Dict[str, Any],
|
|
37
|
+
start_time: float,
|
|
38
|
+
**kwargs: Any,
|
|
39
|
+
) -> None:
|
|
40
|
+
"""Handle the end of a trace event.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
event_type (TraceType): The type of event being traced.
|
|
44
|
+
start_payload (Dict[str, Any]): The payload data from event start.
|
|
45
|
+
end_payload (Dict[str, Any]): The payload data from event end.
|
|
46
|
+
start_time (float): The timestamp when the event started.
|
|
47
|
+
**kwargs (Any): Additional keyword arguments.
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
@abstractmethod
|
|
51
|
+
def on_log(self, message: str, **kwargs: Any) -> None:
|
|
52
|
+
"""Handle a log message during tracing.
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
message (str): The log message.
|
|
56
|
+
**kwargs (Any): Additional keyword arguments.
|
|
57
|
+
"""
|
|
58
|
+
|
|
59
|
+
@abstractmethod
|
|
60
|
+
def on_error(
|
|
61
|
+
self,
|
|
62
|
+
event_type: TraceType,
|
|
63
|
+
start_payload: Dict[str, Any],
|
|
64
|
+
error: Exception,
|
|
65
|
+
start_time: float,
|
|
66
|
+
traceback_info: str,
|
|
67
|
+
**kwargs: Any,
|
|
68
|
+
) -> None:
|
|
69
|
+
"""Handle an error during tracing.
|
|
70
|
+
|
|
71
|
+
Args:
|
|
72
|
+
event_type (TraceType): The type of event being traced.
|
|
73
|
+
start_payload (Dict[str, Any]): The payload data from event start.
|
|
74
|
+
error (Exception): The exception that occurred.
|
|
75
|
+
start_time (float): The timestamp when the event started.
|
|
76
|
+
traceback_info (str): The traceback information.
|
|
77
|
+
**kwargs (Any): Additional keyword arguments.
|
|
78
|
+
"""
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class BaseLogHandler(TracerHandler):
|
|
82
|
+
"""Basic log handler implementation using Python's logging module."""
|
|
83
|
+
|
|
84
|
+
import logging
|
|
85
|
+
|
|
86
|
+
logger = logging.getLogger(__name__)
|
|
87
|
+
|
|
88
|
+
def on_start(
|
|
89
|
+
self,
|
|
90
|
+
event_type: TraceType,
|
|
91
|
+
payload: Dict[str, Any],
|
|
92
|
+
**kwargs: Any,
|
|
93
|
+
) -> None:
|
|
94
|
+
"""Log the start of a trace event.
|
|
95
|
+
|
|
96
|
+
Args:
|
|
97
|
+
event_type (TraceType): The type of event being traced.
|
|
98
|
+
payload (Dict[str, Any]): The payload data for the event.
|
|
99
|
+
**kwargs (Any): Additional keyword arguments.
|
|
100
|
+
"""
|
|
101
|
+
self.logger.info(f"Event {event_type} started with payload: {payload}")
|
|
102
|
+
|
|
103
|
+
def on_end(
|
|
104
|
+
self,
|
|
105
|
+
event_type: TraceType,
|
|
106
|
+
start_payload: Dict[str, Any],
|
|
107
|
+
end_payload: Dict[str, Any],
|
|
108
|
+
start_time: float,
|
|
109
|
+
**kwargs: Any,
|
|
110
|
+
) -> None:
|
|
111
|
+
"""Log the end of a trace event.
|
|
112
|
+
|
|
113
|
+
Args:
|
|
114
|
+
event_type (TraceType): The type of event being traced.
|
|
115
|
+
start_payload (Dict[str, Any]): The payload data from event start.
|
|
116
|
+
end_payload (Dict[str, Any]): The payload data from event end.
|
|
117
|
+
start_time (float): The timestamp when the event started.
|
|
118
|
+
**kwargs (Any): Additional keyword arguments.
|
|
119
|
+
"""
|
|
120
|
+
self.logger.info(
|
|
121
|
+
f"Event {event_type} ended with start payload: {start_payload}, "
|
|
122
|
+
f"end payload: {end_payload}, duration: "
|
|
123
|
+
f"{time.time() - start_time} seconds, kwargs: {kwargs}",
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
def on_log(self, message: str, **kwargs: Any) -> None:
|
|
127
|
+
"""Log a message during tracing.
|
|
128
|
+
|
|
129
|
+
Args:
|
|
130
|
+
message (str): The log message.
|
|
131
|
+
**kwargs (Any): Additional keyword arguments.
|
|
132
|
+
"""
|
|
133
|
+
if message:
|
|
134
|
+
self.logger.info(f"Log: {message}")
|
|
135
|
+
|
|
136
|
+
def on_error(
|
|
137
|
+
self,
|
|
138
|
+
event_type: TraceType,
|
|
139
|
+
start_payload: Dict[str, Any],
|
|
140
|
+
error: Exception,
|
|
141
|
+
start_time: float,
|
|
142
|
+
traceback_info: str,
|
|
143
|
+
**kwargs: Any,
|
|
144
|
+
) -> None:
|
|
145
|
+
"""Log an error during tracing.
|
|
146
|
+
|
|
147
|
+
Args:
|
|
148
|
+
event_type (TraceType): The type of event being traced.
|
|
149
|
+
start_payload (Dict[str, Any]): The payload data from event start.
|
|
150
|
+
error (Exception): The exception that occurred.
|
|
151
|
+
start_time (float): The timestamp when the event started.
|
|
152
|
+
traceback_info (str): The traceback information.
|
|
153
|
+
**kwargs (Any): Additional keyword arguments.
|
|
154
|
+
"""
|
|
155
|
+
self.logger.error(
|
|
156
|
+
f"Error in event {event_type} with payload: {start_payload}, "
|
|
157
|
+
f"error: {error}, "
|
|
158
|
+
f"traceback: {traceback_info}, duration: "
|
|
159
|
+
f"{time.time() - start_time} seconds, kwargs: {kwargs}",
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
class Tracer:
|
|
164
|
+
"""
|
|
165
|
+
Tracer class for logging events
|
|
166
|
+
usage:
|
|
167
|
+
with tracer.event(TraceType.LLM, payload) as event:
|
|
168
|
+
event.log("message")
|
|
169
|
+
""...logic here...""
|
|
170
|
+
end_payload = {xxx}
|
|
171
|
+
# optional on_end call for additional payload and kwargs
|
|
172
|
+
event.on_end(end_payload, if_success=True)
|
|
173
|
+
"""
|
|
174
|
+
|
|
175
|
+
def __init__(self, handlers: List[TracerHandler]):
|
|
176
|
+
"""Initialize the tracer with a list of handlers.
|
|
177
|
+
|
|
178
|
+
Args:
|
|
179
|
+
handlers (List[TracerHandler]): List of handlers to process trace
|
|
180
|
+
events.
|
|
181
|
+
"""
|
|
182
|
+
self.handlers = handlers
|
|
183
|
+
|
|
184
|
+
@contextmanager
|
|
185
|
+
def event(
|
|
186
|
+
self,
|
|
187
|
+
event_type: TraceType,
|
|
188
|
+
payload: Dict[str, Any],
|
|
189
|
+
**kwargs: Any,
|
|
190
|
+
) -> Any:
|
|
191
|
+
"""Create a context manager for tracing an event.
|
|
192
|
+
|
|
193
|
+
Args:
|
|
194
|
+
event_type (TraceType): The type of event being traced.
|
|
195
|
+
payload (Dict[str, Any]): The payload data for the event.
|
|
196
|
+
**kwargs (Any): Additional keyword arguments.
|
|
197
|
+
|
|
198
|
+
Yields:
|
|
199
|
+
EventContext: The event context for logging and managing the trace.
|
|
200
|
+
"""
|
|
201
|
+
start_time = time.time()
|
|
202
|
+
|
|
203
|
+
for handle in self.handlers:
|
|
204
|
+
handle.on_start(event_type, payload, **kwargs)
|
|
205
|
+
|
|
206
|
+
event_context = EventContext(
|
|
207
|
+
self.handlers,
|
|
208
|
+
event_type,
|
|
209
|
+
start_time,
|
|
210
|
+
payload,
|
|
211
|
+
)
|
|
212
|
+
try:
|
|
213
|
+
yield event_context
|
|
214
|
+
except Exception as e:
|
|
215
|
+
traceback_info = traceback.format_exc()
|
|
216
|
+
for handle in self.handlers:
|
|
217
|
+
handle.on_error(
|
|
218
|
+
event_type,
|
|
219
|
+
payload,
|
|
220
|
+
e,
|
|
221
|
+
start_time,
|
|
222
|
+
traceback_info=traceback_info,
|
|
223
|
+
)
|
|
224
|
+
raise
|
|
225
|
+
event_context._end(payload)
|
|
226
|
+
|
|
227
|
+
def log(self, message: str, **kwargs: Any) -> None:
|
|
228
|
+
"""Log a message using all registered handlers.
|
|
229
|
+
|
|
230
|
+
Args:
|
|
231
|
+
message (str): The log message.
|
|
232
|
+
**kwargs (Any): Additional keyword arguments.
|
|
233
|
+
"""
|
|
234
|
+
for handle in self.handlers:
|
|
235
|
+
handle.on_log(message, **kwargs)
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
class EventContext:
|
|
239
|
+
"""Context manager for individual trace events."""
|
|
240
|
+
|
|
241
|
+
def __init__(
|
|
242
|
+
self,
|
|
243
|
+
handlers: List[TracerHandler],
|
|
244
|
+
event_type: TraceType,
|
|
245
|
+
start_time: float,
|
|
246
|
+
start_payload: Dict[str, Any],
|
|
247
|
+
) -> None:
|
|
248
|
+
"""Initialize the event context.
|
|
249
|
+
|
|
250
|
+
Args:
|
|
251
|
+
handlers (List[TracerHandler]): List of handlers to process
|
|
252
|
+
trace events.
|
|
253
|
+
event_type (TraceType): The type of event being traced.
|
|
254
|
+
start_time (float): The timestamp when the event started.
|
|
255
|
+
start_payload (Dict[str, Any]): The payload data from event start.
|
|
256
|
+
"""
|
|
257
|
+
self.handlers = handlers
|
|
258
|
+
self.event_type = event_type
|
|
259
|
+
self.start_time = start_time
|
|
260
|
+
self.start_payload = start_payload
|
|
261
|
+
self.end_payload = {}
|
|
262
|
+
self.kwargs = {}
|
|
263
|
+
|
|
264
|
+
def on_end(self, payload: Dict[str, Any], **kwargs: Any) -> None:
|
|
265
|
+
"""Set the end payload and additional kwargs for the event.
|
|
266
|
+
|
|
267
|
+
Args:
|
|
268
|
+
payload (Dict[str, Any]): The payload data for event end.
|
|
269
|
+
**kwargs (Any): Additional keyword arguments.
|
|
270
|
+
"""
|
|
271
|
+
self.end_payload = payload
|
|
272
|
+
self.kwargs = kwargs
|
|
273
|
+
|
|
274
|
+
def on_log(self, message: str, **kwargs: Any) -> None:
|
|
275
|
+
"""Log a message within this event context.
|
|
276
|
+
|
|
277
|
+
Args:
|
|
278
|
+
message (str): The log message.
|
|
279
|
+
**kwargs (Any): Additional keyword arguments.
|
|
280
|
+
"""
|
|
281
|
+
kwargs["event_type"] = self.event_type
|
|
282
|
+
kwargs["start_time"] = self.start_time
|
|
283
|
+
kwargs["start_payload"] = self.start_payload
|
|
284
|
+
for handle in self.handlers:
|
|
285
|
+
handle.on_log(message, **kwargs)
|
|
286
|
+
|
|
287
|
+
def _end(self, start_payload: Dict[str, Any] = None) -> None:
|
|
288
|
+
"""Finalize the event by calling on_end for all handlers.
|
|
289
|
+
|
|
290
|
+
Args:
|
|
291
|
+
start_payload (Dict[str, Any], optional): The payload data from
|
|
292
|
+
event start.
|
|
293
|
+
"""
|
|
294
|
+
for handle in self.handlers:
|
|
295
|
+
handle.on_end(
|
|
296
|
+
self.event_type,
|
|
297
|
+
start_payload,
|
|
298
|
+
self.end_payload,
|
|
299
|
+
self.start_time,
|
|
300
|
+
**self.kwargs,
|
|
301
|
+
)
|
|
302
|
+
|
|
303
|
+
def set_trace_header(self, trace_header: Dict[str, Any]) -> None:
|
|
304
|
+
"""Set trace header for compatible handlers.
|
|
305
|
+
|
|
306
|
+
Args:
|
|
307
|
+
trace_header (Dict[str, Any]): The trace header information.
|
|
308
|
+
"""
|
|
309
|
+
# TODO: Implement this
|
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
import json
|
|
3
|
+
import logging
|
|
4
|
+
import os
|
|
5
|
+
import time
|
|
6
|
+
from datetime import datetime
|
|
7
|
+
from logging.handlers import RotatingFileHandler
|
|
8
|
+
from typing import Any, Dict, Optional
|
|
9
|
+
|
|
10
|
+
from pydantic import BaseModel
|
|
11
|
+
|
|
12
|
+
from .base import TracerHandler, TraceType
|
|
13
|
+
|
|
14
|
+
DEFAULT_LOG_NAME = "agentscope-runtime"
|
|
15
|
+
|
|
16
|
+
INFO_LOG_FILE_NAME = "info"
|
|
17
|
+
ERROR_LOG_FILE_NAME = "error"
|
|
18
|
+
LOG_EXTENSION = "log"
|
|
19
|
+
DS_SVC_ID = os.getenv("DS_SVC_ID", "test_id")
|
|
20
|
+
DS_SVC_NAME = os.getenv("DS_SVC_NAME", "test_name")
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class LogContext(BaseModel):
|
|
24
|
+
"""Pydantic model for log context data."""
|
|
25
|
+
|
|
26
|
+
time: str = ""
|
|
27
|
+
step: str = ""
|
|
28
|
+
model: str = ""
|
|
29
|
+
user_id: str = ""
|
|
30
|
+
task_id: str = ""
|
|
31
|
+
code: str = ""
|
|
32
|
+
message: str = ""
|
|
33
|
+
request_id: str = ""
|
|
34
|
+
context: Dict = {}
|
|
35
|
+
interval: Dict = {}
|
|
36
|
+
service_id: str = ""
|
|
37
|
+
service_name: str = ""
|
|
38
|
+
ds_service_id: str = ""
|
|
39
|
+
ds_service_name: str = ""
|
|
40
|
+
|
|
41
|
+
class Config:
|
|
42
|
+
extra = "ignore" # ignore additional key
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class JsonFormatter(logging.Formatter):
|
|
46
|
+
"""
|
|
47
|
+
Custom formatter to output logs in llm chat format.
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
def format(self, record: logging.LogRecord) -> str:
|
|
51
|
+
"""Format a log record as JSON.
|
|
52
|
+
|
|
53
|
+
Args:
|
|
54
|
+
record (logging.LogRecord): The log record to format.
|
|
55
|
+
|
|
56
|
+
Returns:
|
|
57
|
+
str: The formatted log record as a JSON string.
|
|
58
|
+
"""
|
|
59
|
+
log_record = {
|
|
60
|
+
"time": datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3],
|
|
61
|
+
"step": getattr(record, "step", None),
|
|
62
|
+
"model": getattr(record, "model", None),
|
|
63
|
+
"user_id": getattr(record, "user_id", None),
|
|
64
|
+
"code": getattr(record, "code", None),
|
|
65
|
+
"message": record.getMessage(),
|
|
66
|
+
"task_id": getattr(record, "task_id", None),
|
|
67
|
+
"request_id": getattr(record, "request_id", None),
|
|
68
|
+
"context": getattr(record, "context", None),
|
|
69
|
+
"interval": getattr(record, "interval", None),
|
|
70
|
+
"ds_service_id": DS_SVC_ID,
|
|
71
|
+
"ds_service_name": DS_SVC_NAME,
|
|
72
|
+
}
|
|
73
|
+
# Clean up any extra fields that are None (not provided)
|
|
74
|
+
log_record = {k: v for k, v in log_record.items() if v is not None}
|
|
75
|
+
if record.exc_info:
|
|
76
|
+
log_record["exc_info"] = self.formatException(record.exc_info)
|
|
77
|
+
return json.dumps(log_record, ensure_ascii=False)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
class LocalLogHandler(TracerHandler):
|
|
81
|
+
"""llm chat log handler for structured JSON logging."""
|
|
82
|
+
|
|
83
|
+
def __init__(
|
|
84
|
+
self,
|
|
85
|
+
log_level: int = logging.INFO,
|
|
86
|
+
log_file_name: Optional[str] = None,
|
|
87
|
+
log_dir: str = f"{os.getcwd()}/logs",
|
|
88
|
+
max_bytes: int = 1024 * 1024 * 1024,
|
|
89
|
+
backup_count: int = 7,
|
|
90
|
+
enable_console: bool = False,
|
|
91
|
+
propagate: bool = False,
|
|
92
|
+
**kwargs: Any,
|
|
93
|
+
) -> None:
|
|
94
|
+
"""Initialize the llm chat log handler.
|
|
95
|
+
|
|
96
|
+
Args:
|
|
97
|
+
log_level (int): The logging level. Defaults to logging.INFO.
|
|
98
|
+
log_file_name (Optional[str]): Prefix for log file names.
|
|
99
|
+
Defaults to None.
|
|
100
|
+
log_dir (str): Directory to save log files. Defaults to "./logs".
|
|
101
|
+
max_bytes (int): Maximum size in bytes for a single log file.
|
|
102
|
+
Defaults to 1GB.
|
|
103
|
+
backup_count (int): Number of log files to keep. Defaults to 7.
|
|
104
|
+
enable_console (bool): Whether to enable console logging.
|
|
105
|
+
Defaults to False.
|
|
106
|
+
propagate (bool): Whether to propagate log messages to parent
|
|
107
|
+
loggers.
|
|
108
|
+
Defaults to False.
|
|
109
|
+
**kwargs (Any): Additional keyword arguments.
|
|
110
|
+
"""
|
|
111
|
+
self.logger = logging.getLogger(DEFAULT_LOG_NAME)
|
|
112
|
+
# Set propagate attribute to control log message propagation
|
|
113
|
+
# Note: Python logging propagate defaults to True, we set it to
|
|
114
|
+
# False by default
|
|
115
|
+
self.logger.propagate = propagate
|
|
116
|
+
|
|
117
|
+
if enable_console:
|
|
118
|
+
handler = logging.StreamHandler()
|
|
119
|
+
handler.setFormatter(JsonFormatter())
|
|
120
|
+
self.logger.addHandler(handler)
|
|
121
|
+
os.makedirs(log_dir, exist_ok=True)
|
|
122
|
+
self._set_file_handle(
|
|
123
|
+
log_dir=log_dir,
|
|
124
|
+
log_file_name=log_file_name,
|
|
125
|
+
max_bytes=max_bytes,
|
|
126
|
+
backup_count=backup_count,
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
self.logger.setLevel(log_level)
|
|
130
|
+
self.kwargs = kwargs
|
|
131
|
+
|
|
132
|
+
def _set_file_handle(
|
|
133
|
+
self,
|
|
134
|
+
log_dir: str,
|
|
135
|
+
log_file_name: Optional[str],
|
|
136
|
+
max_bytes: int,
|
|
137
|
+
backup_count: int,
|
|
138
|
+
) -> None:
|
|
139
|
+
"""Set up file handlers for logging.
|
|
140
|
+
|
|
141
|
+
Args:
|
|
142
|
+
log_dir (str): Directory to save the log files.
|
|
143
|
+
log_file_name (Optional[str]): Prefix name of log file name.
|
|
144
|
+
max_bytes (int): Maximum size in bytes for a single log file.
|
|
145
|
+
backup_count (int): The number of log files to keep.
|
|
146
|
+
"""
|
|
147
|
+
log_file_name_prefix = f"{log_file_name}-" if log_file_name else ""
|
|
148
|
+
|
|
149
|
+
# Create file handlers with JsonFormatter
|
|
150
|
+
info_file_path = os.path.join(
|
|
151
|
+
log_dir,
|
|
152
|
+
f"{log_file_name_prefix}{INFO_LOG_FILE_NAME}.{LOG_EXTENSION}."
|
|
153
|
+
f"{os.getpid()}",
|
|
154
|
+
)
|
|
155
|
+
info_file_handler = RotatingFileHandler(
|
|
156
|
+
info_file_path,
|
|
157
|
+
mode="a",
|
|
158
|
+
maxBytes=max_bytes,
|
|
159
|
+
backupCount=backup_count,
|
|
160
|
+
)
|
|
161
|
+
info_file_handler.setFormatter(JsonFormatter())
|
|
162
|
+
info_file_handler.setLevel(logging.INFO)
|
|
163
|
+
|
|
164
|
+
# Create error file handler
|
|
165
|
+
error_file_path = os.path.join(
|
|
166
|
+
log_dir,
|
|
167
|
+
f"{log_file_name_prefix}{ERROR_LOG_FILE_NAME}.{LOG_EXTENSION}."
|
|
168
|
+
f"{os.getpid()}",
|
|
169
|
+
)
|
|
170
|
+
error_file_handler = RotatingFileHandler(
|
|
171
|
+
error_file_path,
|
|
172
|
+
mode="a",
|
|
173
|
+
maxBytes=max_bytes,
|
|
174
|
+
backupCount=backup_count,
|
|
175
|
+
)
|
|
176
|
+
error_file_handler.setFormatter(JsonFormatter())
|
|
177
|
+
error_file_handler.setLevel(logging.ERROR)
|
|
178
|
+
|
|
179
|
+
# Add handlers to the logger
|
|
180
|
+
self.logger.addHandler(info_file_handler)
|
|
181
|
+
self.logger.addHandler(error_file_handler)
|
|
182
|
+
|
|
183
|
+
@staticmethod
|
|
184
|
+
def _deep_update(original: Dict[str, Any], update: Dict[str, Any]) -> None:
|
|
185
|
+
"""Recursively update a dictionary with another dictionary.
|
|
186
|
+
|
|
187
|
+
Args:
|
|
188
|
+
original (Dict[str, Any]): The original dictionary to update.
|
|
189
|
+
update (Dict[str, Any]): The dictionary containing updates.
|
|
190
|
+
"""
|
|
191
|
+
for key, value in update.items():
|
|
192
|
+
if (
|
|
193
|
+
isinstance(value, dict)
|
|
194
|
+
and key in original
|
|
195
|
+
and isinstance(original[key], dict)
|
|
196
|
+
):
|
|
197
|
+
LocalLogHandler._deep_update(original[key], value)
|
|
198
|
+
else:
|
|
199
|
+
original[key] = value
|
|
200
|
+
|
|
201
|
+
def on_start(
|
|
202
|
+
self,
|
|
203
|
+
event_type: TraceType,
|
|
204
|
+
payload: Dict[str, Any],
|
|
205
|
+
**kwargs: Any,
|
|
206
|
+
) -> None:
|
|
207
|
+
"""Handle the start of a trace event.
|
|
208
|
+
|
|
209
|
+
Args:
|
|
210
|
+
event_type (TraceType): The type of event being traced.
|
|
211
|
+
payload (Dict[str, Any]): The payload data for the event.
|
|
212
|
+
**kwargs (Any): Additional keyword arguments.
|
|
213
|
+
"""
|
|
214
|
+
step = f"{event_type}_start"
|
|
215
|
+
request_id = payload.get("request_id", "")
|
|
216
|
+
context = payload.get("context", payload)
|
|
217
|
+
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
|
|
218
|
+
interval = {"type": step, "cost": 0}
|
|
219
|
+
runtime_context = LogContext(
|
|
220
|
+
time=timestamp,
|
|
221
|
+
step=step,
|
|
222
|
+
interval=interval,
|
|
223
|
+
context=context,
|
|
224
|
+
request_id=request_id,
|
|
225
|
+
)
|
|
226
|
+
try:
|
|
227
|
+
self.logger.info(
|
|
228
|
+
runtime_context.message,
|
|
229
|
+
extra=runtime_context.model_dump(exclude={"message"}),
|
|
230
|
+
)
|
|
231
|
+
except Exception as e:
|
|
232
|
+
import traceback
|
|
233
|
+
|
|
234
|
+
print(traceback.format_exc())
|
|
235
|
+
print(e)
|
|
236
|
+
|
|
237
|
+
def on_end(
|
|
238
|
+
self,
|
|
239
|
+
event_type: TraceType,
|
|
240
|
+
start_payload: Dict[str, Any],
|
|
241
|
+
end_payload: Dict[str, Any],
|
|
242
|
+
start_time: float,
|
|
243
|
+
**kwargs: Any,
|
|
244
|
+
) -> None:
|
|
245
|
+
"""Handle the end of a trace event.
|
|
246
|
+
|
|
247
|
+
Args:
|
|
248
|
+
event_type (TraceType): The type of event being traced.
|
|
249
|
+
start_payload (Dict[str, Any]): The payload data from event start.
|
|
250
|
+
end_payload (Dict[str, Any]): The payload data from event end.
|
|
251
|
+
start_time (float): The timestamp when the event started.
|
|
252
|
+
**kwargs (Any): Additional keyword arguments.
|
|
253
|
+
"""
|
|
254
|
+
|
|
255
|
+
LocalLogHandler._deep_update(end_payload, start_payload)
|
|
256
|
+
|
|
257
|
+
step = f"{event_type}_end"
|
|
258
|
+
request_id = end_payload.get("request_id", "")
|
|
259
|
+
context = end_payload.get("context", end_payload)
|
|
260
|
+
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
|
|
261
|
+
duration = time.time() - start_time
|
|
262
|
+
interval = {"type": step, "cost": f"{duration:.3f}"}
|
|
263
|
+
runtime_context = LogContext(
|
|
264
|
+
time=timestamp,
|
|
265
|
+
step=step,
|
|
266
|
+
interval=interval,
|
|
267
|
+
context=context,
|
|
268
|
+
request_id=request_id,
|
|
269
|
+
)
|
|
270
|
+
self.logger.info(
|
|
271
|
+
runtime_context.message,
|
|
272
|
+
extra=runtime_context.model_dump(exclude={"message"}),
|
|
273
|
+
)
|
|
274
|
+
|
|
275
|
+
def on_log(self, message: str, **kwargs: Any) -> None:
|
|
276
|
+
"""Handle a log message during tracing.
|
|
277
|
+
|
|
278
|
+
Args:
|
|
279
|
+
message (str): The log message.
|
|
280
|
+
**kwargs (Any): Additional keyword arguments including:
|
|
281
|
+
- step_suffix: Optional suffix for step identification
|
|
282
|
+
- event_type: The type of event being traced
|
|
283
|
+
- payload: The payload data
|
|
284
|
+
- start_time: The timestamp when the event started
|
|
285
|
+
- start_payload: The payload data from event start
|
|
286
|
+
"""
|
|
287
|
+
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
|
|
288
|
+
if "step_suffix" in kwargs:
|
|
289
|
+
step_suffix = kwargs["step_suffix"]
|
|
290
|
+
event_type = kwargs["event_type"]
|
|
291
|
+
payload = kwargs["payload"]
|
|
292
|
+
start_time = kwargs["start_time"]
|
|
293
|
+
start_payload = kwargs["start_payload"]
|
|
294
|
+
|
|
295
|
+
LocalLogHandler._deep_update(payload, start_payload)
|
|
296
|
+
|
|
297
|
+
step = f"{event_type}_{step_suffix}"
|
|
298
|
+
duration = time.time() - start_time
|
|
299
|
+
interval = {"type": step, "cost": f"{duration:.3f}"}
|
|
300
|
+
else:
|
|
301
|
+
step = ""
|
|
302
|
+
interval = {"type": step, "cost": "0"}
|
|
303
|
+
payload = {}
|
|
304
|
+
|
|
305
|
+
runtime_context = LogContext(
|
|
306
|
+
time=timestamp,
|
|
307
|
+
step=step,
|
|
308
|
+
interval=interval,
|
|
309
|
+
context=payload,
|
|
310
|
+
message=message,
|
|
311
|
+
)
|
|
312
|
+
self.logger.info(
|
|
313
|
+
runtime_context.message,
|
|
314
|
+
extra=runtime_context.model_dump(exclude={"message"}),
|
|
315
|
+
)
|
|
316
|
+
|
|
317
|
+
def on_error(
|
|
318
|
+
self,
|
|
319
|
+
event_type: TraceType,
|
|
320
|
+
start_payload: Dict[str, Any],
|
|
321
|
+
error: Exception,
|
|
322
|
+
start_time: float,
|
|
323
|
+
traceback_info: str,
|
|
324
|
+
**kwargs: Any,
|
|
325
|
+
) -> None:
|
|
326
|
+
"""Handle an error during tracing.
|
|
327
|
+
|
|
328
|
+
Args:
|
|
329
|
+
event_type (TraceType): The type of event being traced.
|
|
330
|
+
start_payload (Dict[str, Any]): The payload data from event start.
|
|
331
|
+
error (Exception): The exception that occurred.
|
|
332
|
+
start_time (float): The timestamp when the event started.
|
|
333
|
+
traceback_info (str): The traceback information.
|
|
334
|
+
**kwargs (Any): Additional keyword arguments.
|
|
335
|
+
"""
|
|
336
|
+
step = f"{event_type}_error"
|
|
337
|
+
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
|
|
338
|
+
duration = time.time() - start_time
|
|
339
|
+
interval = {"type": step, "cost": f"{duration:.3f}"}
|
|
340
|
+
if "context" not in start_payload:
|
|
341
|
+
start_payload["context"] = {}
|
|
342
|
+
start_payload["context"].update(
|
|
343
|
+
{"type": error.__class__.__name__, "details": traceback_info},
|
|
344
|
+
)
|
|
345
|
+
runtime_context = LogContext(
|
|
346
|
+
time=timestamp,
|
|
347
|
+
step=step,
|
|
348
|
+
interval=interval,
|
|
349
|
+
code=error.__class__.__name__,
|
|
350
|
+
message=str(error),
|
|
351
|
+
**start_payload,
|
|
352
|
+
)
|
|
353
|
+
self.logger.error(
|
|
354
|
+
runtime_context.message,
|
|
355
|
+
extra=runtime_context.model_dump(exclude={"message"}),
|
|
356
|
+
)
|