veadk-python 0.2.9__py3-none-any.whl → 0.2.11__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.

Potentially problematic release.


This version of veadk-python might be problematic. Click here for more details.

Files changed (46) hide show
  1. veadk/a2a/remote_ve_agent.py +63 -6
  2. veadk/agent.py +10 -3
  3. veadk/agent_builder.py +2 -3
  4. veadk/auth/veauth/ark_veauth.py +43 -51
  5. veadk/auth/veauth/utils.py +57 -0
  6. veadk/cli/cli.py +2 -0
  7. veadk/cli/cli_kb.py +75 -0
  8. veadk/cli/cli_web.py +4 -0
  9. veadk/configs/model_configs.py +3 -3
  10. veadk/consts.py +9 -0
  11. veadk/integrations/__init__.py +13 -0
  12. veadk/integrations/ve_viking_db_memory/__init__.py +13 -0
  13. veadk/integrations/ve_viking_db_memory/ve_viking_db_memory.py +293 -0
  14. veadk/knowledgebase/knowledgebase.py +19 -32
  15. veadk/memory/__init__.py +1 -1
  16. veadk/memory/long_term_memory.py +40 -68
  17. veadk/memory/long_term_memory_backends/base_backend.py +4 -2
  18. veadk/memory/long_term_memory_backends/in_memory_backend.py +8 -6
  19. veadk/memory/long_term_memory_backends/mem0_backend.py +25 -10
  20. veadk/memory/long_term_memory_backends/opensearch_backend.py +40 -36
  21. veadk/memory/long_term_memory_backends/redis_backend.py +59 -46
  22. veadk/memory/long_term_memory_backends/vikingdb_memory_backend.py +56 -35
  23. veadk/memory/short_term_memory.py +12 -8
  24. veadk/memory/short_term_memory_backends/postgresql_backend.py +3 -1
  25. veadk/runner.py +42 -19
  26. veadk/tools/builtin_tools/generate_image.py +56 -17
  27. veadk/tools/builtin_tools/image_edit.py +17 -7
  28. veadk/tools/builtin_tools/image_generate.py +17 -7
  29. veadk/tools/builtin_tools/load_knowledgebase.py +97 -0
  30. veadk/tools/builtin_tools/video_generate.py +11 -9
  31. veadk/tools/builtin_tools/web_search.py +10 -3
  32. veadk/tools/load_knowledgebase_tool.py +12 -0
  33. veadk/tracing/telemetry/attributes/extractors/llm_attributes_extractors.py +5 -0
  34. veadk/tracing/telemetry/attributes/extractors/tool_attributes_extractors.py +7 -0
  35. veadk/tracing/telemetry/exporters/apmplus_exporter.py +82 -2
  36. veadk/tracing/telemetry/exporters/inmemory_exporter.py +8 -2
  37. veadk/tracing/telemetry/telemetry.py +41 -5
  38. veadk/utils/misc.py +6 -10
  39. veadk/utils/volcengine_sign.py +2 -0
  40. veadk/version.py +1 -1
  41. {veadk_python-0.2.9.dist-info → veadk_python-0.2.11.dist-info}/METADATA +4 -3
  42. {veadk_python-0.2.9.dist-info → veadk_python-0.2.11.dist-info}/RECORD +46 -40
  43. {veadk_python-0.2.9.dist-info → veadk_python-0.2.11.dist-info}/WHEEL +0 -0
  44. {veadk_python-0.2.9.dist-info → veadk_python-0.2.11.dist-info}/entry_points.txt +0 -0
  45. {veadk_python-0.2.9.dist-info → veadk_python-0.2.11.dist-info}/licenses/LICENSE +0 -0
  46. {veadk_python-0.2.9.dist-info → veadk_python-0.2.11.dist-info}/top_level.txt +0 -0
veadk/runner.py CHANGED
@@ -12,8 +12,8 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- import os
16
15
  import functools
16
+ import os
17
17
  from types import MethodType
18
18
  from typing import Union
19
19
 
@@ -34,7 +34,7 @@ from veadk.evaluation import EvalSetRecorder
34
34
  from veadk.memory.short_term_memory import ShortTermMemory
35
35
  from veadk.types import MediaMessage
36
36
  from veadk.utils.logger import get_logger
37
- from veadk.utils.misc import formatted_timestamp, read_png_to_bytes
37
+ from veadk.utils.misc import formatted_timestamp, read_file_to_bytes
38
38
 
39
39
  logger = get_logger(__name__)
40
40
 
@@ -50,11 +50,7 @@ RunnerMessage = Union[
50
50
  async def pre_run_process(self, process_func, new_message, user_id, session_id):
51
51
  if new_message.parts:
52
52
  for part in new_message.parts:
53
- if (
54
- part.inline_data
55
- and part.inline_data.mime_type == "image/png"
56
- and self.upload_inline_data_to_tos
57
- ):
53
+ if part.inline_data and self.upload_inline_data_to_tos:
58
54
  await process_func(
59
55
  part,
60
56
  self.app_name,
@@ -105,9 +101,20 @@ def _convert_messages(
105
101
  if isinstance(messages, str):
106
102
  _messages = [types.Content(role="user", parts=[types.Part(text=messages)])]
107
103
  elif isinstance(messages, MediaMessage):
108
- assert messages.media.endswith(".png"), (
109
- "The MediaMessage only supports PNG format file for now."
104
+ import filetype
105
+
106
+ file_data = read_file_to_bytes(messages.media)
107
+
108
+ kind = filetype.guess(file_data)
109
+ if kind is None:
110
+ raise ValueError("Unsupported or unknown file type.")
111
+
112
+ mime_type = kind.mime
113
+
114
+ assert mime_type.startswith(("image/", "video/")), (
115
+ f"Unsupported media type: {mime_type}"
110
116
  )
117
+
111
118
  _messages = [
112
119
  types.Content(
113
120
  role="user",
@@ -116,8 +123,8 @@ def _convert_messages(
116
123
  types.Part(
117
124
  inline_data=Blob(
118
125
  display_name=messages.media,
119
- data=read_png_to_bytes(messages.media),
120
- mime_type="image/png",
126
+ data=file_data,
127
+ mime_type=mime_type,
121
128
  )
122
129
  ),
123
130
  ],
@@ -249,15 +256,21 @@ class Runner(ADKRunner):
249
256
  )
250
257
 
251
258
  if self.short_term_memory:
252
- await self.short_term_memory.create_session(
253
- app_name=self.app_name, user_id=self.user_id, session_id=session_id
259
+ session = await self.short_term_memory.create_session(
260
+ app_name=self.app_name, user_id=user_id, session_id=session_id
261
+ )
262
+ assert session, (
263
+ f"Failed to create session with app_name={self.app_name}, user_id={user_id}, session_id={session_id}, "
264
+ )
265
+ logger.debug(
266
+ f"Auto create session: {session.id}, user_id: {session.user_id}, app_name: {self.app_name}"
254
267
  )
255
268
 
256
269
  final_output = ""
257
270
  for converted_message in converted_messages:
258
271
  try:
259
272
  async for event in self.run_async(
260
- user_id=self.user_id,
273
+ user_id=user_id,
261
274
  session_id=session_id,
262
275
  new_message=converted_message,
263
276
  run_config=run_config,
@@ -271,7 +284,8 @@ class Runner(ADKRunner):
271
284
  and event.content.parts[0].text is not None
272
285
  and len(event.content.parts[0].text.strip()) > 0
273
286
  ):
274
- final_output += event.content.parts[0].text
287
+ final_output = event.content.parts[0].text
288
+ logger.debug(f"Event output: {final_output}")
275
289
  except LlmCallsLimitExceededError as e:
276
290
  logger.warning(f"Max number of llm calls limit exceeded: {e}")
277
291
  final_output = ""
@@ -359,19 +373,28 @@ class Runner(ADKRunner):
359
373
  )
360
374
  return eval_set_path
361
375
 
362
- async def save_session_to_long_term_memory(self, session_id: str) -> None:
376
+ async def save_session_to_long_term_memory(
377
+ self, session_id: str, user_id: str = "", app_name: str = ""
378
+ ) -> None:
363
379
  if not self.long_term_memory:
364
380
  logger.warning("Long-term memory is not enabled. Failed to save session.")
365
381
  return
366
382
 
383
+ if not user_id:
384
+ user_id = self.user_id
385
+
386
+ if not app_name:
387
+ app_name = self.app_name
388
+
367
389
  session = await self.session_service.get_session(
368
- app_name=self.app_name,
369
- user_id=self.user_id,
390
+ app_name=app_name,
391
+ user_id=user_id,
370
392
  session_id=session_id,
371
393
  )
394
+
372
395
  if not session:
373
396
  logger.error(
374
- f"Session {session_id} not found in session service, cannot save to long-term memory."
397
+ f"Session {session_id} (app_name={app_name}, user_id={user_id}) not found in session service, cannot save to long-term memory."
375
398
  )
376
399
  return
377
400
 
@@ -12,28 +12,35 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
+ import base64
16
+ import json
17
+ import mimetypes
18
+ import traceback
15
19
  from typing import Dict
16
20
 
17
21
  from google.adk.tools import ToolContext
18
- from veadk.config import getenv
19
- from veadk.consts import DEFAULT_IMAGE_GENERATE_MODEL_NAME, DEFAULT_MODEL_AGENT_API_BASE
20
-
21
- import base64
22
- from volcenginesdkarkruntime import Ark
22
+ from google.genai.types import Blob, Part
23
23
  from opentelemetry import trace
24
- import traceback
25
- from veadk.version import VERSION
26
24
  from opentelemetry.trace import Span
27
- from veadk.utils.logger import get_logger
25
+ from volcenginesdkarkruntime import Ark
28
26
  from volcenginesdkarkruntime.types.images.images import SequentialImageGenerationOptions
29
- import json
30
27
 
28
+ from veadk.config import getenv, settings
29
+ from veadk.consts import (
30
+ DEFAULT_IMAGE_GENERATE_MODEL_NAME,
31
+ DEFAULT_IMAGE_GENERATE_MODEL_API_BASE,
32
+ )
33
+ from veadk.utils.logger import get_logger
34
+ from veadk.utils.misc import formatted_timestamp, read_file_to_bytes
35
+ from veadk.version import VERSION
31
36
 
32
37
  logger = get_logger(__name__)
33
38
 
34
39
  client = Ark(
35
- api_key=getenv("MODEL_AGENT_API_KEY"),
36
- base_url=DEFAULT_MODEL_AGENT_API_BASE,
40
+ api_key=getenv(
41
+ "MODEL_IMAGE_API_KEY", getenv("MODEL_AGENT_API_KEY", settings.model.api_key)
42
+ ),
43
+ base_url=getenv("MODEL_IMAGE_API_BASE", DEFAULT_IMAGE_GENERATE_MODEL_API_BASE),
37
44
  )
38
45
 
39
46
 
@@ -121,7 +128,7 @@ async def image_generate(
121
128
  - size 推荐使用 2048x2048 或表格里的标准比例,确保生成质量。
122
129
  """
123
130
 
124
- success_list = []
131
+ success_list: list[dict] = []
125
132
  error_list = []
126
133
 
127
134
  for idx, item in enumerate(tasks):
@@ -184,7 +191,9 @@ async def image_generate(
184
191
  and max_images
185
192
  ):
186
193
  response = client.images.generate(
187
- model=DEFAULT_IMAGE_GENERATE_MODEL_NAME,
194
+ model=getenv(
195
+ "MODEL_IMAGE_NAME", DEFAULT_IMAGE_GENERATE_MODEL_NAME
196
+ ),
188
197
  **inputs,
189
198
  sequential_image_generation_options=SequentialImageGenerationOptions(
190
199
  max_images=max_images
@@ -192,7 +201,10 @@ async def image_generate(
192
201
  )
193
202
  else:
194
203
  response = client.images.generate(
195
- model=DEFAULT_IMAGE_GENERATE_MODEL_NAME, **inputs
204
+ model=getenv(
205
+ "MODEL_IMAGE_NAME", DEFAULT_IMAGE_GENERATE_MODEL_NAME
206
+ ),
207
+ **inputs,
196
208
  )
197
209
  if not response.error:
198
210
  for i, image_data in enumerate(response.data):
@@ -261,8 +273,12 @@ async def image_generate(
261
273
  output_part=output_part,
262
274
  output_tokens=output_tokens,
263
275
  total_tokens=total_tokens,
264
- request_model=DEFAULT_IMAGE_GENERATE_MODEL_NAME,
265
- response_model=DEFAULT_IMAGE_GENERATE_MODEL_NAME,
276
+ request_model=getenv(
277
+ "MODEL_IMAGE_NAME", DEFAULT_IMAGE_GENERATE_MODEL_NAME
278
+ ),
279
+ response_model=getenv(
280
+ "MODEL_IMAGE_NAME", DEFAULT_IMAGE_GENERATE_MODEL_NAME
281
+ ),
266
282
  )
267
283
  if len(success_list) == 0:
268
284
  return {
@@ -271,6 +287,28 @@ async def image_generate(
271
287
  "error_list": error_list,
272
288
  }
273
289
  else:
290
+ app_name = tool_context._invocation_context.app_name
291
+ user_id = tool_context._invocation_context.user_id
292
+ session_id = tool_context._invocation_context.session.id
293
+
294
+ artifact_service = tool_context._invocation_context.artifact_service
295
+ if artifact_service:
296
+ for image in success_list:
297
+ for _, image_tos_url in image.items():
298
+ filename = f"artifact_{formatted_timestamp()}"
299
+ await artifact_service.save_artifact(
300
+ app_name=app_name,
301
+ user_id=user_id,
302
+ session_id=session_id,
303
+ filename=filename,
304
+ artifact=Part(
305
+ inline_data=Blob(
306
+ display_name=filename,
307
+ data=read_file_to_bytes(image_tos_url),
308
+ mime_type=mimetypes.guess_type(image_tos_url)[0],
309
+ )
310
+ ),
311
+ )
274
312
  return {
275
313
  "status": "success",
276
314
  "success_list": success_list,
@@ -332,10 +370,11 @@ def add_span_attributes(
332
370
 
333
371
  def _upload_image_to_tos(image_bytes: bytes, object_key: str) -> None:
334
372
  try:
335
- from veadk.integrations.ve_tos.ve_tos import VeTOS
336
373
  import os
337
374
  from datetime import datetime
338
375
 
376
+ from veadk.integrations.ve_tos.ve_tos import VeTOS
377
+
339
378
  timestamp: str = datetime.now().strftime("%Y%m%d%H%M%S%f")[:-3]
340
379
  object_key = f"{timestamp}-{object_key}"
341
380
  bucket_name = os.getenv("DATABASE_TOS_BUCKET")
@@ -15,8 +15,11 @@
15
15
  from typing import Dict
16
16
  from google.adk.tools import ToolContext
17
17
  from volcenginesdkarkruntime import Ark
18
- from veadk.config import getenv
19
- from veadk.consts import DEFAULT_MODEL_AGENT_API_BASE, DEFAULT_IMAGE_EDIT_MODEL_NAME
18
+ from veadk.config import getenv, settings
19
+ from veadk.consts import (
20
+ DEFAULT_IMAGE_EDIT_MODEL_API_BASE,
21
+ DEFAULT_IMAGE_EDIT_MODEL_NAME,
22
+ )
20
23
  import base64
21
24
  from opentelemetry import trace
22
25
  import traceback
@@ -28,8 +31,10 @@ from veadk.utils.logger import get_logger
28
31
  logger = get_logger(__name__)
29
32
 
30
33
  client = Ark(
31
- api_key=getenv("MODEL_AGENT_API_KEY"),
32
- base_url=DEFAULT_MODEL_AGENT_API_BASE,
34
+ api_key=getenv(
35
+ "MODEL_EDIT_API_KEY", getenv("MODEL_AGENT_API_KEY", settings.model.api_key)
36
+ ),
37
+ base_url=getenv("MODEL_EDIT_API_BASE", DEFAULT_IMAGE_EDIT_MODEL_API_BASE),
33
38
  )
34
39
 
35
40
 
@@ -123,7 +128,8 @@ async def image_edit(
123
128
  "parts.1.image_url.url": origin_image,
124
129
  }
125
130
  response = client.images.generate(
126
- model=DEFAULT_IMAGE_EDIT_MODEL_NAME, **inputs
131
+ model=getenv("MODEL_EDIT_NAME", DEFAULT_IMAGE_EDIT_MODEL_NAME),
132
+ **inputs,
127
133
  )
128
134
  output_part = None
129
135
  if response.data and len(response.data) > 0:
@@ -175,8 +181,12 @@ async def image_edit(
175
181
  output_part=output_part,
176
182
  output_tokens=response.usage.output_tokens,
177
183
  total_tokens=response.usage.total_tokens,
178
- request_model=DEFAULT_IMAGE_EDIT_MODEL_NAME,
179
- response_model=DEFAULT_IMAGE_EDIT_MODEL_NAME,
184
+ request_model=getenv(
185
+ "MODEL_EDIT_NAME", DEFAULT_IMAGE_EDIT_MODEL_NAME
186
+ ),
187
+ response_model=getenv(
188
+ "MODEL_EDIT_NAME", DEFAULT_IMAGE_EDIT_MODEL_NAME
189
+ ),
180
190
  )
181
191
 
182
192
  except Exception as e:
@@ -15,8 +15,11 @@
15
15
  from typing import Dict
16
16
 
17
17
  from google.adk.tools import ToolContext
18
- from veadk.config import getenv
19
- from veadk.consts import DEFAULT_TEXT_TO_IMAGE_MODEL_NAME, DEFAULT_MODEL_AGENT_API_BASE
18
+ from veadk.config import getenv, settings
19
+ from veadk.consts import (
20
+ DEFAULT_TEXT_TO_IMAGE_MODEL_NAME,
21
+ DEFAULT_TEXT_TO_IMAGE_MODEL_API_BASE,
22
+ )
20
23
  import base64
21
24
  from volcenginesdkarkruntime import Ark
22
25
  from opentelemetry import trace
@@ -29,8 +32,10 @@ from veadk.utils.logger import get_logger
29
32
  logger = get_logger(__name__)
30
33
 
31
34
  client = Ark(
32
- api_key=getenv("MODEL_AGENT_API_KEY"),
33
- base_url=DEFAULT_MODEL_AGENT_API_BASE,
35
+ api_key=getenv(
36
+ "MODEL_IMAGE_API_KEY", getenv("MODEL_AGENT_API_KEY", settings.model.api_key)
37
+ ),
38
+ base_url=getenv("MODEL_IMAGE_API_BASE", DEFAULT_TEXT_TO_IMAGE_MODEL_API_BASE),
34
39
  )
35
40
 
36
41
 
@@ -120,7 +125,8 @@ async def image_generate(
120
125
  "content": json.dumps(inputs, ensure_ascii=False),
121
126
  }
122
127
  response = client.images.generate(
123
- model=DEFAULT_TEXT_TO_IMAGE_MODEL_NAME, **inputs
128
+ model=getenv("MODEL_IMAGE_NAME", DEFAULT_TEXT_TO_IMAGE_MODEL_NAME),
129
+ **inputs,
124
130
  )
125
131
  output_part = None
126
132
  if response.data and len(response.data) > 0:
@@ -172,8 +178,12 @@ async def image_generate(
172
178
  output_part=output_part,
173
179
  output_tokens=response.usage.output_tokens,
174
180
  total_tokens=response.usage.total_tokens,
175
- request_model=DEFAULT_TEXT_TO_IMAGE_MODEL_NAME,
176
- response_model=DEFAULT_TEXT_TO_IMAGE_MODEL_NAME,
181
+ request_model=getenv(
182
+ "MODEL_IMAGE_NAME", DEFAULT_TEXT_TO_IMAGE_MODEL_NAME
183
+ ),
184
+ response_model=getenv(
185
+ "MODEL_IMAGE_NAME", DEFAULT_TEXT_TO_IMAGE_MODEL_NAME
186
+ ),
177
187
  )
178
188
 
179
189
  except Exception as e:
@@ -0,0 +1,97 @@
1
+ # Copyright (c) 2025 Beijing Volcano Engine Technology Co., Ltd. and/or its affiliates.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ from __future__ import annotations
16
+
17
+ from google.adk.models.llm_request import LlmRequest
18
+ from google.adk.tools.function_tool import FunctionTool
19
+ from google.adk.tools.tool_context import ToolContext
20
+ from google.genai import types
21
+ from pydantic import BaseModel, Field
22
+ from typing_extensions import override
23
+
24
+ from veadk.knowledgebase import KnowledgeBase
25
+ from veadk.knowledgebase.entry import KnowledgebaseEntry
26
+ from veadk.utils.logger import get_logger
27
+
28
+ logger = get_logger(__name__)
29
+
30
+
31
+ class LoadKnowledgebaseResponse(BaseModel):
32
+ knowledges: list[KnowledgebaseEntry] = Field(default_factory=list)
33
+
34
+
35
+ class LoadKnowledgebaseTool(FunctionTool):
36
+ """A tool that loads the common knowledgebase"""
37
+
38
+ def __init__(self, knowledgebase: KnowledgeBase):
39
+ super().__init__(self.load_knowledgebase)
40
+
41
+ self.knowledgebase = knowledgebase
42
+
43
+ if not self.custom_metadata:
44
+ self.custom_metadata = {}
45
+ self.custom_metadata["backend"] = knowledgebase.backend
46
+
47
+ @override
48
+ def _get_declaration(self) -> types.FunctionDeclaration | None:
49
+ return types.FunctionDeclaration(
50
+ name=self.name,
51
+ description=self.description,
52
+ parameters=types.Schema(
53
+ type=types.Type.OBJECT,
54
+ properties={
55
+ "query": types.Schema(
56
+ type=types.Type.STRING,
57
+ )
58
+ },
59
+ required=["query"],
60
+ ),
61
+ )
62
+
63
+ @override
64
+ async def process_llm_request(
65
+ self,
66
+ *,
67
+ tool_context: ToolContext,
68
+ llm_request: LlmRequest,
69
+ ) -> None:
70
+ await super().process_llm_request(
71
+ tool_context=tool_context, llm_request=llm_request
72
+ )
73
+ # Tell the model about the knowledgebase.
74
+ llm_request.append_instructions(
75
+ [
76
+ f"""
77
+ You have a knowledgebase (knowledegebase name is `{self.knowledgebase.name}`, knowledgebase description is `{self.knowledgebase.description}`). You can use it to answer questions. If any questions need
78
+ you to look up the knowledgebase, you should call load_knowledgebase function with a query.
79
+ """
80
+ ]
81
+ )
82
+
83
+ async def load_knowledgebase(
84
+ self, query: str, tool_context: ToolContext
85
+ ) -> LoadKnowledgebaseResponse:
86
+ """Loads the knowledgebase for the user.
87
+
88
+ Args:
89
+ query: The query to load the knowledgebase for.
90
+
91
+ Returns:
92
+ A list of knowledgebase results.
93
+ """
94
+ logger.info(f"Search knowledgebase: {self.knowledgebase.name}")
95
+ response = self.knowledgebase.search(query)
96
+ logger.info(f"Loaded {len(response)} knowledgebase entries for query: {query}")
97
+ return LoadKnowledgebaseResponse(knowledges=response)
@@ -25,16 +25,18 @@ from volcenginesdkarkruntime.types.content_generation.create_task_content_param
25
25
  CreateTaskContentParam,
26
26
  )
27
27
 
28
- from veadk.config import getenv
29
- from veadk.consts import DEFAULT_MODEL_AGENT_API_BASE, DEFAULT_VIDEO_MODEL_NAME
28
+ from veadk.config import getenv, settings
29
+ from veadk.consts import DEFAULT_VIDEO_MODEL_API_BASE, DEFAULT_VIDEO_MODEL_NAME
30
30
  from veadk.utils.logger import get_logger
31
31
  from veadk.version import VERSION
32
32
 
33
33
  logger = get_logger(__name__)
34
34
 
35
35
  client = Ark(
36
- api_key=getenv("MODEL_AGENT_API_KEY"),
37
- base_url=DEFAULT_MODEL_AGENT_API_BASE,
36
+ api_key=getenv(
37
+ "MODEL_VIDEO_API_KEY", getenv("MODEL_AGENT_API_KEY", settings.model.api_key)
38
+ ),
39
+ base_url=getenv("MODEL_VIDEO_API_BASE", DEFAULT_VIDEO_MODEL_API_BASE),
38
40
  )
39
41
 
40
42
 
@@ -43,7 +45,7 @@ async def generate(prompt, first_frame_image=None, last_frame_image=None):
43
45
  if first_frame_image is None:
44
46
  logger.debug("text generation")
45
47
  response = client.content_generation.tasks.create(
46
- model=DEFAULT_VIDEO_MODEL_NAME,
48
+ model=getenv("MODEL_VIDEO_NAME", DEFAULT_VIDEO_MODEL_NAME),
47
49
  content=[
48
50
  {"type": "text", "text": prompt},
49
51
  ],
@@ -51,7 +53,7 @@ async def generate(prompt, first_frame_image=None, last_frame_image=None):
51
53
  elif last_frame_image is None:
52
54
  logger.debug("first frame generation")
53
55
  response = client.content_generation.tasks.create(
54
- model=DEFAULT_VIDEO_MODEL_NAME,
56
+ model=getenv("MODEL_VIDEO_NAME", DEFAULT_VIDEO_MODEL_NAME),
55
57
  content=cast(
56
58
  list[CreateTaskContentParam], # avoid IDE warning
57
59
  [
@@ -66,7 +68,7 @@ async def generate(prompt, first_frame_image=None, last_frame_image=None):
66
68
  else:
67
69
  logger.debug("last frame generation")
68
70
  response = client.content_generation.tasks.create(
69
- model=DEFAULT_VIDEO_MODEL_NAME,
71
+ model=getenv("MODEL_VIDEO_NAME", DEFAULT_VIDEO_MODEL_NAME),
70
72
  content=[
71
73
  {"type": "text", "text": prompt},
72
74
  {
@@ -263,8 +265,8 @@ async def video_generate(params: list, tool_context: ToolContext) -> Dict:
263
265
  output_part=output_part,
264
266
  output_tokens=total_tokens,
265
267
  total_tokens=total_tokens,
266
- request_model=DEFAULT_VIDEO_MODEL_NAME,
267
- response_model=DEFAULT_VIDEO_MODEL_NAME,
268
+ request_model=getenv("MODEL_VIDEO_NAME", DEFAULT_VIDEO_MODEL_NAME),
269
+ response_model=getenv("MODEL_VIDEO_NAME", DEFAULT_VIDEO_MODEL_NAME),
268
270
  )
269
271
 
270
272
  if len(success_list) == 0:
@@ -23,6 +23,7 @@ import json
23
23
  from urllib.parse import quote
24
24
 
25
25
  import requests
26
+ from google.adk.tools import ToolContext
26
27
 
27
28
  from veadk.config import getenv
28
29
  from veadk.utils.logger import get_logger
@@ -151,7 +152,7 @@ def request(method, date, query, header, ak, sk, action, body):
151
152
  return r.json()
152
153
 
153
154
 
154
- def web_search(query: str) -> list[str]:
155
+ def web_search(query: str, tool_context: ToolContext) -> list[str]:
155
156
  """Search a query in websites.
156
157
 
157
158
  Args:
@@ -166,8 +167,14 @@ def web_search(query: str) -> list[str]:
166
167
  "Count": 5,
167
168
  "NeedSummary": True,
168
169
  }
169
- ak = getenv("VOLCENGINE_ACCESS_KEY")
170
- sk = getenv("VOLCENGINE_SECRET_KEY")
170
+
171
+ ak = tool_context.state.get("VOLCENGINE_ACCESS_KEY")
172
+ if not ak:
173
+ ak = getenv("VOLCENGINE_ACCESS_KEY")
174
+
175
+ sk = tool_context.state.get("VOLCENGINE_SECRET_KEY")
176
+ if not sk:
177
+ sk = getenv("VOLCENGINE_SECRET_KEY")
171
178
 
172
179
  now = datetime.datetime.utcnow()
173
180
  response_body = request(
@@ -25,6 +25,9 @@ from typing_extensions import override
25
25
 
26
26
  from veadk.knowledgebase import KnowledgeBase
27
27
  from veadk.knowledgebase.entry import KnowledgebaseEntry
28
+ from veadk.utils.logger import get_logger
29
+
30
+ logger = get_logger(__name__)
28
31
 
29
32
  if TYPE_CHECKING:
30
33
  from google.adk.models.llm_request import LlmRequest
@@ -96,6 +99,15 @@ class LoadKnowledgebaseTool(FunctionTool):
96
99
 
97
100
  def __init__(self):
98
101
  super().__init__(load_knowledgebase)
102
+ global knowledgebase
103
+ if knowledgebase is None:
104
+ logger.info(
105
+ "Get global knowledgebase instance failed, failed to set knowledgebase tool backend."
106
+ )
107
+ else:
108
+ if not self.custom_metadata:
109
+ self.custom_metadata = {}
110
+ self.custom_metadata["backend"] = knowledgebase.backend
99
111
 
100
112
  @override
101
113
  def _get_declaration(self) -> types.FunctionDeclaration | None:
@@ -325,6 +325,10 @@ def llm_gen_ai_operation_name(params: LLMAttributesParams) -> ExtractorResponse:
325
325
  return ExtractorResponse(content="chat")
326
326
 
327
327
 
328
+ def llm_gen_ai_span_kind(params: LLMAttributesParams) -> ExtractorResponse:
329
+ return ExtractorResponse(content="llm")
330
+
331
+
328
332
  # def llm_gen_ai_system_message(params: LLMAttributesParams) -> ExtractorResponse:
329
333
  # event_attributes = {
330
334
  # "content": str(params.llm_request.config.system_instruction),
@@ -559,6 +563,7 @@ LLM_ATTRIBUTES = {
559
563
  "gen_ai.is_streaming": llm_gen_ai_is_streaming,
560
564
  # -> 1.4. span kind
561
565
  "gen_ai.operation.name": llm_gen_ai_operation_name,
566
+ "gen_ai.span.kind": llm_gen_ai_span_kind, # apmplus required
562
567
  # -> 1.5. inputs
563
568
  "gen_ai.prompt": llm_gen_ai_prompt,
564
569
  # -> 1.6. outputs
@@ -23,6 +23,10 @@ def tool_gen_ai_operation_name(params: ToolAttributesParams) -> ExtractorRespons
23
23
  return ExtractorResponse(content="execute_tool")
24
24
 
25
25
 
26
+ def tool_gen_ai_span_kind(params: ToolAttributesParams) -> ExtractorResponse:
27
+ return ExtractorResponse(content="tool")
28
+
29
+
26
30
  def tool_gen_ai_tool_message(params: ToolAttributesParams) -> ExtractorResponse:
27
31
  tool_input = {
28
32
  "role": "tool",
@@ -73,4 +77,7 @@ TOOL_ATTRIBUTES = {
73
77
  "gen_ai.tool.output": tool_gen_ai_tool_output, # TLS required
74
78
  "cozeloop.input": tool_gen_ai_tool_input, # CozeLoop required
75
79
  "cozeloop.output": tool_gen_ai_tool_output, # CozeLoop required
80
+ "gen_ai.span.kind": tool_gen_ai_span_kind, # apmplus required
81
+ "gen_ai.input": tool_gen_ai_tool_input, # apmplus required
82
+ "gen_ai.output": tool_gen_ai_tool_output, # apmplus required
76
83
  }