veadk-python 0.2.16__py3-none-any.whl → 0.2.17__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 (64) hide show
  1. veadk/a2a/remote_ve_agent.py +56 -1
  2. veadk/agent.py +79 -26
  3. veadk/agents/loop_agent.py +22 -9
  4. veadk/agents/parallel_agent.py +21 -9
  5. veadk/agents/sequential_agent.py +18 -9
  6. veadk/auth/veauth/apmplus_veauth.py +32 -39
  7. veadk/auth/veauth/ark_veauth.py +3 -1
  8. veadk/auth/veauth/utils.py +12 -0
  9. veadk/auth/veauth/viking_mem0_veauth.py +91 -0
  10. veadk/cli/cli.py +5 -1
  11. veadk/cli/cli_create.py +62 -1
  12. veadk/cli/cli_deploy.py +36 -1
  13. veadk/cli/cli_eval.py +55 -0
  14. veadk/cli/cli_init.py +44 -3
  15. veadk/cli/cli_kb.py +36 -1
  16. veadk/cli/cli_pipeline.py +66 -1
  17. veadk/cli/cli_prompt.py +16 -1
  18. veadk/cli/cli_uploadevalset.py +15 -1
  19. veadk/cli/cli_web.py +35 -4
  20. veadk/cloud/cloud_agent_engine.py +142 -25
  21. veadk/cloud/cloud_app.py +219 -12
  22. veadk/configs/database_configs.py +4 -0
  23. veadk/configs/model_configs.py +5 -1
  24. veadk/configs/tracing_configs.py +2 -2
  25. veadk/evaluation/adk_evaluator/adk_evaluator.py +77 -17
  26. veadk/evaluation/base_evaluator.py +219 -3
  27. veadk/evaluation/deepeval_evaluator/deepeval_evaluator.py +116 -1
  28. veadk/evaluation/eval_set_file_loader.py +20 -0
  29. veadk/evaluation/eval_set_recorder.py +54 -0
  30. veadk/evaluation/types.py +32 -0
  31. veadk/evaluation/utils/prometheus.py +61 -0
  32. veadk/knowledgebase/backends/base_backend.py +14 -1
  33. veadk/knowledgebase/backends/in_memory_backend.py +10 -1
  34. veadk/knowledgebase/backends/opensearch_backend.py +26 -0
  35. veadk/knowledgebase/backends/redis_backend.py +29 -2
  36. veadk/knowledgebase/backends/vikingdb_knowledge_backend.py +43 -5
  37. veadk/knowledgebase/knowledgebase.py +173 -12
  38. veadk/memory/long_term_memory.py +148 -4
  39. veadk/memory/long_term_memory_backends/mem0_backend.py +11 -0
  40. veadk/memory/short_term_memory.py +119 -5
  41. veadk/runner.py +412 -1
  42. veadk/tools/builtin_tools/llm_shield.py +381 -0
  43. veadk/tools/builtin_tools/mcp_router.py +9 -2
  44. veadk/tools/builtin_tools/run_code.py +25 -5
  45. veadk/tools/builtin_tools/web_search.py +38 -154
  46. veadk/tracing/base_tracer.py +28 -1
  47. veadk/tracing/telemetry/attributes/extractors/common_attributes_extractors.py +105 -1
  48. veadk/tracing/telemetry/attributes/extractors/llm_attributes_extractors.py +260 -0
  49. veadk/tracing/telemetry/attributes/extractors/tool_attributes_extractors.py +69 -0
  50. veadk/tracing/telemetry/attributes/extractors/types.py +78 -0
  51. veadk/tracing/telemetry/exporters/apmplus_exporter.py +157 -0
  52. veadk/tracing/telemetry/exporters/base_exporter.py +8 -0
  53. veadk/tracing/telemetry/exporters/cozeloop_exporter.py +60 -1
  54. veadk/tracing/telemetry/exporters/inmemory_exporter.py +118 -1
  55. veadk/tracing/telemetry/exporters/tls_exporter.py +66 -0
  56. veadk/tracing/telemetry/opentelemetry_tracer.py +111 -1
  57. veadk/tracing/telemetry/telemetry.py +118 -2
  58. veadk/version.py +1 -1
  59. {veadk_python-0.2.16.dist-info → veadk_python-0.2.17.dist-info}/METADATA +1 -1
  60. {veadk_python-0.2.16.dist-info → veadk_python-0.2.17.dist-info}/RECORD +64 -62
  61. {veadk_python-0.2.16.dist-info → veadk_python-0.2.17.dist-info}/WHEEL +0 -0
  62. {veadk_python-0.2.16.dist-info → veadk_python-0.2.17.dist-info}/entry_points.txt +0 -0
  63. {veadk_python-0.2.16.dist-info → veadk_python-0.2.17.dist-info}/licenses/LICENSE +0 -0
  64. {veadk_python-0.2.16.dist-info → veadk_python-0.2.17.dist-info}/top_level.txt +0 -0
@@ -50,20 +50,87 @@ def wrap_get_session_with_callbacks(obj, callback_fn: Callable):
50
50
 
51
51
 
52
52
  class ShortTermMemory(BaseModel):
53
+ """Short term memory for agent execution.
54
+
55
+ The short term memory represents the context of the agent model. All content in the short term memory will be sent to agent model directly, including the system prompt, historical user prompt, and historical model responses.
56
+
57
+ Attributes:
58
+ backend (Literal["local", "mysql", "sqlite", "postgresql", "database"]):
59
+ The backend of short term memory:
60
+ - `local` for in-memory storage
61
+ - `mysql` for mysql / PostgreSQL storage
62
+ - `sqlite` for locally sqlite storage
63
+ backend_configs (dict): Configuration dict for init short term memory backend.
64
+ db_url (str):
65
+ Database connection url for init short term memory backend.
66
+ For example, `sqlite:///./test.db`. Once set, it will override the `backend` parameter.
67
+ local_database_path (str):
68
+ Local database path, only used when `backend` is `sqlite`.
69
+ Default to `/tmp/veadk_local_database.db`.
70
+ after_load_memory_callback (Callable | None):
71
+ A callback to be called after loading memory from the backend. The callback function should accept `Session` as an input.
72
+
73
+ Examples:
74
+ ### In-memory simple memory
75
+
76
+ You can initialize a short term memory with in-memory storage:
77
+
78
+ ```python
79
+ from veadk import Agent, Runner
80
+ from veadk.memory.short_term_memory import ShortTermMemory
81
+ import asyncio
82
+
83
+ session_id = "veadk_playground_session"
84
+
85
+ agent = Agent()
86
+ short_term_memory = ShortTermMemory(backend="local")
87
+
88
+ runner = Runner(
89
+ agent=agent, short_term_memory=short_term_memory)
90
+
91
+ # This invocation will be stored in short-term memory
92
+ response = asyncio.run(runner.run(
93
+ messages="My name is VeADK", session_id=session_id
94
+ ))
95
+ print(response)
96
+
97
+ # The history invocation can be fetched by model
98
+ response = asyncio.run(runner.run(
99
+ messages="Do you remember my name?", session_id=session_id # keep the same `session_id`
100
+ ))
101
+ print(response)
102
+ ```
103
+
104
+ ### Memory with a Database URL
105
+
106
+ Also you can use a databasae connection URL to initialize a short-term memory:
107
+
108
+ ```python
109
+ from veadk.memory.short_term_memory import ShortTermMemory
110
+
111
+ short_term_memory = ShortTermMemory(db_url="...")
112
+ ```
113
+
114
+ ### Memory with SQLite
115
+
116
+ Once you want to start the short term memory with a local SQLite, you can specify the backend to `sqlite`. It will create a local database in `local_database_path`:
117
+
118
+ ```python
119
+ from veadk.memory.short_term_memory import ShortTermMemory
120
+
121
+ short_term_memory = ShortTermMemory(backend="sqlite", local_database_path="")
122
+ ```
123
+ """
124
+
53
125
  backend: Literal["local", "mysql", "sqlite", "postgresql", "database"] = "local"
54
- """Short term memory backend. `Local` for in-memory storage, `mysql` for mysql / PostgreSQL storage. `sqlite` for sqlite storage."""
55
126
 
56
127
  backend_configs: dict = Field(default_factory=dict)
57
- """Backend specific configurations."""
58
128
 
59
129
  db_url: str = ""
60
- """Database connection URL, e.g. `sqlite:///./test.db`. Once set, it will override the `backend` parameter."""
61
130
 
62
131
  local_database_path: str = "/tmp/veadk_local_database.db"
63
- """Local database path, only used when `backend` is `sqlite`. Default to `/tmp/veadk_local_database.db`."""
64
132
 
65
133
  after_load_memory_callback: Callable | None = None
66
- """A callback to be called after loading memory from the backend. The callback function should accept `Session` as an input."""
67
134
 
68
135
  _session_service: BaseSessionService = PrivateAttr()
69
136
 
@@ -108,6 +175,53 @@ class ShortTermMemory(BaseModel):
108
175
  user_id: str,
109
176
  session_id: str,
110
177
  ) -> Session | None:
178
+ """Create or retrieve a user session.
179
+
180
+ Short term memory can attempt to create a new session for a given application and user. If a session with the same `session_id` already exists, it will be returned instead of creating a new one.
181
+
182
+ If the underlying session service is backed by a database (`DatabaseSessionService`), the method first lists all existing sessions for the given `app_name` and `user_id` and logs the number of sessions found. It then checks whether a session with the specified `session_id` already exists:
183
+ - If it exists → returns the existing session.
184
+ - If it does not exist → creates and returns a new session.
185
+
186
+ Args:
187
+ app_name (str): The name of the application associated with the session.
188
+ user_id (str): The unique identifier of the user.
189
+ session_id (str): The unique identifier of the session to be created or retrieved.
190
+
191
+ Returns:
192
+ Session | None: The retrieved or newly created `Session` object, or `None` if the session creation failed.
193
+
194
+ Examples:
195
+ Create a new session manually:
196
+
197
+ ```python
198
+ import asyncio
199
+
200
+ from veadk.memory import ShortTermMemory
201
+
202
+ app_name = "app_name"
203
+ user_id = "user_id"
204
+ session_id = "session_id"
205
+
206
+ short_term_memory = ShortTermMemory()
207
+
208
+ session = asyncio.run(
209
+ short_term_memory.create_session(
210
+ app_name=app_name, user_id=user_id, session_id=session_id
211
+ )
212
+ )
213
+
214
+ print(session)
215
+
216
+ session = asyncio.run(
217
+ short_term_memory.session_service.get_session(
218
+ app_name=app_name, user_id=user_id, session_id=session_id
219
+ )
220
+ )
221
+
222
+ print(session)
223
+ ```
224
+ """
111
225
  if isinstance(self._session_service, DatabaseSessionService):
112
226
  list_sessions_response = await self._session_service.list_sessions(
113
227
  app_name=app_name, user_id=user_id
veadk/runner.py CHANGED
@@ -48,6 +48,28 @@ RunnerMessage = Union[
48
48
 
49
49
 
50
50
  async def pre_run_process(self, process_func, new_message, user_id, session_id):
51
+ """Pre-run hook invoked before agent execution.
52
+
53
+ Iterates over all ``parts`` of ``new_message`` and, when a ``part`` contains
54
+ ``inline_data`` and uploading is enabled, calls ``process_func`` to process
55
+ the data (for example, upload to TOS and rewrite with an accessible URL).
56
+ Typically used together with the ``intercept_new_message`` decorator.
57
+
58
+ Args:
59
+ self: Runner instance.
60
+ process_func: An async processing function with a signature like
61
+ ``(part, app_name, user_id, session_id)`` used to handle
62
+ ``inline_data`` in the message (e.g., upload to TOS).
63
+ new_message (google.genai.types.Content): Incoming user message.
64
+ user_id (str): User identifier.
65
+ session_id (str): Session identifier.
66
+
67
+ Returns:
68
+ None
69
+
70
+ Raises:
71
+ Exception: Propagated if ``process_func`` raises and does not handle it.
72
+ """
51
73
  if new_message.parts:
52
74
  for part in new_message.parts:
53
75
  if part.inline_data and self.upload_inline_data_to_tos:
@@ -60,10 +82,42 @@ async def pre_run_process(self, process_func, new_message, user_id, session_id):
60
82
 
61
83
 
62
84
  def post_run_process(self):
85
+ """Post-run hook executed after agent run.
86
+
87
+ This is currently a no-op placeholder and can be extended to perform
88
+ cleanup or finalize logic after a run.
89
+
90
+ Args:
91
+ self: Runner instance.
92
+
93
+ Returns:
94
+ None
95
+
96
+ Raises:
97
+ None
98
+ """
63
99
  return
64
100
 
65
101
 
66
102
  def intercept_new_message(process_func):
103
+ """Create a decorator to insert pre/post hooks around ``run_async`` calls.
104
+
105
+ Internally it invokes :func:`pre_run_process` to preprocess the incoming
106
+ message (e.g., upload image/video inline data to TOS), then iterates the
107
+ underlying event stream and finally calls :func:`post_run_process`.
108
+
109
+ Args:
110
+ process_func: Async function used to process ``inline_data`` (typically
111
+ ``_upload_image_to_tos``).
112
+
113
+ Returns:
114
+ Callable: A decorator that can wrap ``run_async``.
115
+
116
+ Raises:
117
+ Exception: May propagate exceptions raised by the wrapped function or
118
+ the pre-processing step.
119
+ """
120
+
67
121
  def decorator(func):
68
122
  @functools.wraps(func)
69
123
  async def wrapper(
@@ -97,7 +151,34 @@ def _convert_messages(
97
151
  user_id: str,
98
152
  session_id: str,
99
153
  ) -> list:
100
- """Convert VeADK formatted messages to Google ADK formatted messages."""
154
+ """Convert a VeADK ``RunnerMessage`` into a list of Google ADK messages.
155
+
156
+ Supported inputs:
157
+ - ``str``: Single-turn text prompt.
158
+ - :class:`veadk.types.MediaMessage`: Single-turn multimodal prompt (text + image/video).
159
+ - ``list``: A list of the above types (multi-turn with mixed text and multimodal).
160
+
161
+ For multimodal inputs, this reads the local media file bytes and detects
162
+ the MIME type via ``filetype``; only ``image/*`` and ``video/*`` are supported.
163
+
164
+ Args:
165
+ messages (RunnerMessage): Input message or list of messages to convert.
166
+ app_name (str): App name (not directly used; kept for consistency with upload path).
167
+ user_id (str): User ID (not directly used; kept for consistency with upload path).
168
+ session_id (str): Session ID (not directly used; kept for consistency with upload path).
169
+
170
+ Returns:
171
+ list[google.genai.types.Content]: Converted ADK messages.
172
+
173
+ Raises:
174
+ ValueError: If the message type is unknown or media type is unrecognized.
175
+ AssertionError: If the media MIME type is not supported (only image/* and video/*).
176
+
177
+ Note:
178
+ This function only performs structural conversion. To upload inline media
179
+ to an object store and rewrite URLs, use it together with
180
+ ``intercept_new_message`` and ``_upload_image_to_tos``.
181
+ """
101
182
  if isinstance(messages, str):
102
183
  _messages = [types.Content(role="user", parts=[types.Part(text=messages)])]
103
184
  elif isinstance(messages, MediaMessage):
@@ -146,6 +227,25 @@ def _convert_messages(
146
227
  async def _upload_image_to_tos(
147
228
  part: genai.types.Part, app_name: str, user_id: str, session_id: str
148
229
  ) -> None:
230
+ """Upload inline media data in a message part to TOS and rewrite its URL.
231
+
232
+ When ``part.inline_data`` has both ``display_name`` (original filename) and
233
+ ``data`` (bytes), it generates an object storage path based on
234
+ ``app_name``, ``user_id`` and ``session_id``. After upload, it replaces
235
+ ``display_name`` with a signed URL.
236
+
237
+ Args:
238
+ part (google.genai.types.Part): Message part containing ``inline_data``.
239
+ app_name (str): App name.
240
+ user_id (str): User ID.
241
+ session_id (str): Session ID.
242
+
243
+ Returns:
244
+ None
245
+
246
+ Raises:
247
+ None: All exceptions are caught and logged; nothing is propagated.
248
+ """
149
249
  try:
150
250
  if part.inline_data and part.inline_data.display_name and part.inline_data.data:
151
251
  from veadk.integrations.ve_tos.ve_tos import VeTOS
@@ -164,6 +264,153 @@ async def _upload_image_to_tos(
164
264
 
165
265
 
166
266
  class Runner(ADKRunner):
267
+ """VeADK Runner that augments ADK with session, memory, tracing, and media upload.
268
+
269
+ This class builds on Google ADK's ``Runner`` and adds:
270
+ - Integration with short-term memory (ShortTermMemory) for auto session management.
271
+ - Optional long-term memory integration and session persistence.
272
+ - New message interception and media upload to TOS.
273
+ - Tracing dump and Trace ID logging.
274
+ - A simplified ``run`` entry that supports multi-turn text/multimodal inputs.
275
+
276
+ Attributes:
277
+ user_id (str): Default user ID.
278
+ long_term_memory: Long-term memory service instance, or ``None`` if not set.
279
+ short_term_memory (veadk.memory.short_term_memory.ShortTermMemory | None):
280
+ Short-term memory instance used to auto-create/manage sessions.
281
+ upload_inline_data_to_tos (bool): Whether to upload inline media to TOS while running.
282
+ session_service: Session service instance (may come from short-term memory).
283
+ memory_service: Memory service instance (may come from agent's long-term memory).
284
+ app_name (str): Application name used in session management and object pathing.
285
+
286
+ Note:
287
+ This class wraps the parent ``run_async`` at initialization to insert media
288
+ upload and post-run handling. If you override the underlying ``run_async``,
289
+ ensure it remains compatible with this interception logic.
290
+
291
+ Examples:
292
+ ### Text-only interaction
293
+
294
+ ```python
295
+ import asyncio
296
+
297
+ from veadk import Agent, Runner
298
+
299
+ agent = Agent()
300
+
301
+ runner = Runner(agent=agent)
302
+
303
+ response = asyncio.run(runner.run(messages="北京的天气怎么样?"))
304
+
305
+ print(response)
306
+ ```
307
+
308
+ ### Send multimodal data to agent
309
+
310
+ Currently, VeADK support send multimodal data (i.e., text with images) to agent, and invoke the corresponding model to do tasks.
311
+
312
+ !!! info "Note for multimodal running"
313
+
314
+ When sending multimodal data to agent, the model of agent must support multimodal data processing. For example, `doubao-1-6`.
315
+
316
+ ```python
317
+ import asyncio
318
+
319
+ from veadk import Agent, Runner
320
+ from veadk.types import MediaMessage
321
+
322
+ agent = Agent(model_name="doubao-seed-1-6-250615")
323
+
324
+ runner = Runner(agent=agent)
325
+
326
+ message = MediaMessage(
327
+ text="Describe the image",
328
+ media="https://...", # <-- replace here with an image from web
329
+ )
330
+ response = asyncio.run(runner.run(messages=message))
331
+
332
+ print(response)
333
+ ```
334
+
335
+ ### Run with run_async
336
+
337
+ You are recommand that **using `run_async` in production to invoke agent**. During running, the loop will throw out `event`, you can process each `event` according to your requirements.
338
+
339
+ ```python
340
+ import uuid
341
+
342
+ from google.genai import types
343
+ from veadk import Agent, Runner
344
+
345
+ APP_NAME = "app"
346
+ USER_ID = "user"
347
+
348
+ agent = Agent()
349
+
350
+ runner = Runner(agent=agent, app_name=APP_NAME)
351
+
352
+
353
+ async def main(message: types.Content, session_id: str):
354
+ # before running, you should create a session first
355
+ await runner.short_term_memory.create_session(
356
+ app_name=APP_NAME, user_id=USER_ID, session_id=session_id
357
+ )
358
+
359
+ async for event in runner.run_async(
360
+ user_id=USER_ID,
361
+ session_id=session_id,
362
+ new_message=message,
363
+ ):
364
+ # process event here
365
+ print(event)
366
+
367
+
368
+ if __name__ == "__main__":
369
+ import asyncio
370
+
371
+ message = types.Content(parts=[types.Part(text="Hello")], role="user")
372
+ session_id = str(uuid.uuid1())
373
+ asyncio.run(main(message=message, session_id=session_id))
374
+ ```
375
+
376
+ ### Custom your message
377
+
378
+ You can custom your message content, as Google provides some basic types to build and custom agent's input. For example, you can build a message with a text and several images.
379
+
380
+ ```python
381
+ from google.genai import types
382
+
383
+ # build message with a text
384
+ message = types.Content(parts=[types.Part(text="Hello")], role="user")
385
+
386
+ # build message with a text and an image
387
+ message = types.Content(
388
+ parts=[
389
+ types.Part(text="Hello!"),
390
+ types.Part(
391
+ inline_data=types.Blob(display_name="foo.png", data=..., mime_type=...)
392
+ ),
393
+ ],
394
+ role="user",
395
+ )
396
+
397
+ # build image with several text and several images
398
+ message = types.Content(
399
+ parts=[
400
+ types.Part(text="Hello!"),
401
+ types.Part(text="Please help me to describe the following images."),
402
+ types.Part(
403
+ inline_data=types.Blob(display_name="foo.png", data=..., mime_type=...)
404
+ ),
405
+ types.Part(
406
+ inline_data=types.Blob(display_name="bar.png", data=..., mime_type=...)
407
+ ),
408
+ ],
409
+ role="user",
410
+ )
411
+ ```
412
+ """
413
+
167
414
  def __init__(
168
415
  self,
169
416
  agent: BaseAgent | Agent,
@@ -174,6 +421,33 @@ class Runner(ADKRunner):
174
421
  *args,
175
422
  **kwargs,
176
423
  ) -> None:
424
+ """Initialize a Runner instance.
425
+
426
+ Selects the session service based on provided short-term memory or an
427
+ external ``session_service``. If long-term memory or an external
428
+ ``memory_service`` is provided, the passed service is preferred. After
429
+ construction, it injects a message interception layer into the parent's
430
+ ``run_async`` to support inline media upload and post-run handling.
431
+
432
+ Args:
433
+ agent (google.adk.agents.base_agent.BaseAgent | veadk.agent.Agent):
434
+ The agent instance used to run interactions.
435
+ short_term_memory (ShortTermMemory | None): Optional short-term memory; if
436
+ not provided and no external ``session_service`` is supplied, an in-memory
437
+ session service will be created.
438
+ app_name (str): Application name. Defaults to ``"veadk_default_app"``.
439
+ user_id (str): Default user ID. Defaults to ``"veadk_default_user"``.
440
+ upload_inline_data_to_tos (bool): Whether to enable inline media upload. Defaults to ``False``.
441
+ *args: Positional args passed through to ``ADKRunner``.
442
+ **kwargs: Keyword args passed through to ``ADKRunner``; may include
443
+ ``session_service`` and ``memory_service`` to override defaults.
444
+
445
+ Returns:
446
+ None
447
+
448
+ Raises:
449
+ None
450
+ """
177
451
  self.user_id = user_id
178
452
  self.long_term_memory = None
179
453
  self.short_term_memory = short_term_memory
@@ -238,6 +512,30 @@ class Runner(ADKRunner):
238
512
  save_tracing_data: bool = False,
239
513
  upload_inline_data_to_tos: bool = False,
240
514
  ):
515
+ """Run a conversation with multi-turn text and multimodal inputs.
516
+
517
+ When short-term memory is configured, a session is auto-created as needed.
518
+ Inputs are converted into ADK message format. If ``upload_inline_data_to_tos``
519
+ is ``True``, media upload is enabled temporarily for this run (does not change
520
+ the Runner's global setting).
521
+
522
+ Args:
523
+ messages (RunnerMessage): Input messages (``str``, ``MediaMessage`` or a list of them).
524
+ user_id (str): Override default user ID; if empty, uses the constructed ``user_id``.
525
+ session_id (str): Session ID. Defaults to a timestamp-based temporary ID.
526
+ run_config (google.adk.agents.RunConfig | None): Run config; if ``None``, a default
527
+ config is created using the environment var ``MODEL_AGENT_MAX_LLM_CALLS``.
528
+ save_tracing_data (bool): Whether to dump tracing data to disk after the run. Defaults to ``False``.
529
+ upload_inline_data_to_tos (bool): Whether to enable media upload only for this run. Defaults to ``False``.
530
+
531
+ Returns:
532
+ str: The textual output from the last event, if present; otherwise an empty string.
533
+
534
+ Raises:
535
+ ValueError: If an input contains an unsupported or unrecognized media type.
536
+ AssertionError: If a media MIME type is not among ``image/*`` or ``video/*``.
537
+ Exception: Exceptions from the underlying ADK/Agent execution may propagate.
538
+ """
241
539
  if upload_inline_data_to_tos:
242
540
  _upload_inline_data_to_tos = self.upload_inline_data_to_tos
243
541
  self.upload_inline_data_to_tos = upload_inline_data_to_tos
@@ -302,6 +600,17 @@ class Runner(ADKRunner):
302
600
  return final_output
303
601
 
304
602
  def get_trace_id(self) -> str:
603
+ """Get the Trace ID from the current agent's tracer.
604
+
605
+ If the agent is not a :class:`veadk.agent.Agent` or no tracer is configured,
606
+ returns ``"<unknown_trace_id>"``.
607
+
608
+ Returns:
609
+ str: The Trace ID or ``"<unknown_trace_id>"``.
610
+
611
+ Raises:
612
+ None
613
+ """
305
614
  if not isinstance(self.agent, Agent):
306
615
  logger.warning(
307
616
  ("The agent is not an instance of VeADK Agent, no trace id provided.")
@@ -322,6 +631,17 @@ class Runner(ADKRunner):
322
631
  return "<unknown_trace_id>"
323
632
 
324
633
  def _print_trace_id(self) -> None:
634
+ """Log the current tracer's Trace ID.
635
+
636
+ If the agent is not a :class:`veadk.agent.Agent` or no tracer is configured,
637
+ nothing is printed.
638
+
639
+ Returns:
640
+ None
641
+
642
+ Raises:
643
+ None
644
+ """
325
645
  if not isinstance(self.agent, Agent):
326
646
  logger.warning(
327
647
  ("The agent is not an instance of VeADK Agent, no trace id provided.")
@@ -342,6 +662,37 @@ class Runner(ADKRunner):
342
662
  return
343
663
 
344
664
  def save_tracing_file(self, session_id: str) -> str:
665
+ """Dump tracing data to disk and return the last written path.
666
+
667
+ Only effective when the agent is one of
668
+ Agent/SequentialAgent/ParallelAgent/LoopAgent and a tracer is configured;
669
+ otherwise returns an empty string.
670
+
671
+ Args:
672
+ session_id (str): Session ID used to associate the tracing with a session.
673
+
674
+ Returns:
675
+ str: The tracing file path; returns an empty string on failure or when no tracer.
676
+
677
+ Examples:
678
+ You can save the tracing data to a local file.
679
+
680
+ ```python
681
+ import asyncio
682
+
683
+ from veadk import Agent, Runner
684
+
685
+ agent = Agent()
686
+
687
+ runner = Runner(agent=agent)
688
+
689
+ session_id = "session"
690
+ asyncio.run(runner.run(messages="Hi!", session_id=session_id))
691
+
692
+ path = runner.save_tracing_file(session_id=session_id)
693
+ print(path)
694
+ ```
695
+ """
345
696
  if not isinstance(
346
697
  self.agent, (Agent, SequentialAgent, ParallelAgent, LoopAgent)
347
698
  ):
@@ -367,6 +718,34 @@ class Runner(ADKRunner):
367
718
  return ""
368
719
 
369
720
  async def save_eval_set(self, session_id: str, eval_set_id: str = "default") -> str:
721
+ """Save the current session as part of an evaluation set and return its path.
722
+
723
+ Args:
724
+ session_id (str): Session ID.
725
+ eval_set_id (str): Evaluation set identifier. Defaults to ``"default"``.
726
+
727
+ Returns:
728
+ str: The exported evaluation set file path.
729
+
730
+ Examples:
731
+ You can save the specific session as a evaluation set in Google ADK format.
732
+
733
+ ```python
734
+ import asyncio
735
+
736
+ from veadk import Agent, Runner
737
+
738
+ agent = Agent()
739
+
740
+ runner = Runner(agent=agent)
741
+
742
+ session_id = "session"
743
+ asyncio.run(runner.run(messages="Hi!", session_id=session_id))
744
+
745
+ path = runner.save_eval_set(session_id=session_id)
746
+ print(path)
747
+ ```
748
+ """
370
749
  eval_set_recorder = EvalSetRecorder(self.session_service, eval_set_id)
371
750
  eval_set_path = await eval_set_recorder.dump(
372
751
  self.app_name, self.user_id, session_id
@@ -376,6 +755,38 @@ class Runner(ADKRunner):
376
755
  async def save_session_to_long_term_memory(
377
756
  self, session_id: str, user_id: str = "", app_name: str = ""
378
757
  ) -> None:
758
+ """Save the specified session to long-term memory.
759
+
760
+ If ``long_term_memory`` is not configured, the function logs a warning and returns.
761
+ It fetches the session from the session service and then calls the long-term memory's
762
+ ``add_session_to_memory`` for persistence.
763
+
764
+ Args:
765
+ session_id (str): Session ID.
766
+ user_id (str): Optional; override default user ID. If empty, uses ``self.user_id``.
767
+ app_name (str): Optional; override default app name. If empty, uses ``self.app_name``.
768
+
769
+ Examples:
770
+ You can save a specific session to long-term memory.
771
+
772
+ ```python
773
+ import asyncio
774
+
775
+ from veadk import Agent, Runner
776
+ from veadk.memory import LongTermMemory
777
+
778
+ APP_NAME = "app"
779
+
780
+ agent = Agent(long_term_memory=LongTermMemory(backend="local", app_name=APP_NAME))
781
+
782
+ session_id = "session"
783
+ runner = Runner(agent=agent, app_name=APP_NAME)
784
+
785
+ asyncio.run(runner.run(messages="Hi!", session_id=session_id))
786
+
787
+ asyncio.run(runner.save_session_to_long_term_memory(session_id=session_id))
788
+ ```
789
+ """
379
790
  if not self.long_term_memory:
380
791
  logger.warning("Long-term memory is not enabled. Failed to save session.")
381
792
  return