veadk-python 0.2.27__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 (218) hide show
  1. veadk/__init__.py +37 -0
  2. veadk/a2a/__init__.py +13 -0
  3. veadk/a2a/agent_card.py +45 -0
  4. veadk/a2a/remote_ve_agent.py +390 -0
  5. veadk/a2a/utils/__init__.py +13 -0
  6. veadk/a2a/utils/agent_to_a2a.py +170 -0
  7. veadk/a2a/ve_a2a_server.py +93 -0
  8. veadk/a2a/ve_agent_executor.py +78 -0
  9. veadk/a2a/ve_middlewares.py +313 -0
  10. veadk/a2a/ve_task_store.py +37 -0
  11. veadk/agent.py +402 -0
  12. veadk/agent_builder.py +93 -0
  13. veadk/agents/loop_agent.py +68 -0
  14. veadk/agents/parallel_agent.py +72 -0
  15. veadk/agents/sequential_agent.py +64 -0
  16. veadk/auth/__init__.py +13 -0
  17. veadk/auth/base_auth.py +22 -0
  18. veadk/auth/ve_credential_service.py +203 -0
  19. veadk/auth/veauth/__init__.py +13 -0
  20. veadk/auth/veauth/apmplus_veauth.py +58 -0
  21. veadk/auth/veauth/ark_veauth.py +75 -0
  22. veadk/auth/veauth/base_veauth.py +50 -0
  23. veadk/auth/veauth/cozeloop_veauth.py +13 -0
  24. veadk/auth/veauth/opensearch_veauth.py +75 -0
  25. veadk/auth/veauth/postgresql_veauth.py +75 -0
  26. veadk/auth/veauth/prompt_pilot_veauth.py +60 -0
  27. veadk/auth/veauth/speech_veauth.py +54 -0
  28. veadk/auth/veauth/utils.py +69 -0
  29. veadk/auth/veauth/vesearch_veauth.py +62 -0
  30. veadk/auth/veauth/viking_mem0_veauth.py +91 -0
  31. veadk/cli/__init__.py +13 -0
  32. veadk/cli/cli.py +58 -0
  33. veadk/cli/cli_clean.py +87 -0
  34. veadk/cli/cli_create.py +163 -0
  35. veadk/cli/cli_deploy.py +233 -0
  36. veadk/cli/cli_eval.py +215 -0
  37. veadk/cli/cli_init.py +214 -0
  38. veadk/cli/cli_kb.py +110 -0
  39. veadk/cli/cli_pipeline.py +285 -0
  40. veadk/cli/cli_prompt.py +86 -0
  41. veadk/cli/cli_update.py +106 -0
  42. veadk/cli/cli_uploadevalset.py +139 -0
  43. veadk/cli/cli_web.py +143 -0
  44. veadk/cloud/__init__.py +13 -0
  45. veadk/cloud/cloud_agent_engine.py +485 -0
  46. veadk/cloud/cloud_app.py +475 -0
  47. veadk/config.py +115 -0
  48. veadk/configs/__init__.py +13 -0
  49. veadk/configs/auth_configs.py +133 -0
  50. veadk/configs/database_configs.py +132 -0
  51. veadk/configs/model_configs.py +78 -0
  52. veadk/configs/tool_configs.py +54 -0
  53. veadk/configs/tracing_configs.py +110 -0
  54. veadk/consts.py +74 -0
  55. veadk/evaluation/__init__.py +17 -0
  56. veadk/evaluation/adk_evaluator/__init__.py +17 -0
  57. veadk/evaluation/adk_evaluator/adk_evaluator.py +302 -0
  58. veadk/evaluation/base_evaluator.py +642 -0
  59. veadk/evaluation/deepeval_evaluator/__init__.py +17 -0
  60. veadk/evaluation/deepeval_evaluator/deepeval_evaluator.py +339 -0
  61. veadk/evaluation/eval_set_file_loader.py +48 -0
  62. veadk/evaluation/eval_set_recorder.py +146 -0
  63. veadk/evaluation/types.py +65 -0
  64. veadk/evaluation/utils/prometheus.py +196 -0
  65. veadk/integrations/__init__.py +13 -0
  66. veadk/integrations/ve_apig/__init__.py +13 -0
  67. veadk/integrations/ve_apig/ve_apig.py +349 -0
  68. veadk/integrations/ve_apig/ve_apig_utils.py +332 -0
  69. veadk/integrations/ve_code_pipeline/__init__.py +13 -0
  70. veadk/integrations/ve_code_pipeline/ve_code_pipeline.py +431 -0
  71. veadk/integrations/ve_cozeloop/__init__.py +13 -0
  72. veadk/integrations/ve_cozeloop/ve_cozeloop.py +96 -0
  73. veadk/integrations/ve_cr/__init__.py +13 -0
  74. veadk/integrations/ve_cr/ve_cr.py +220 -0
  75. veadk/integrations/ve_faas/__init__.py +13 -0
  76. veadk/integrations/ve_faas/template/cookiecutter.json +15 -0
  77. veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/__init__.py +13 -0
  78. veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/clean.py +23 -0
  79. veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/config.yaml.example +6 -0
  80. veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/deploy.py +106 -0
  81. veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/__init__.py +13 -0
  82. veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/agent.py +25 -0
  83. veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/app.py +202 -0
  84. veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/requirements.txt +3 -0
  85. veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/run.sh +49 -0
  86. veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/{{ cookiecutter.app_name }}/__init__.py +14 -0
  87. veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/{{ cookiecutter.app_name }}/agent.py +27 -0
  88. veadk/integrations/ve_faas/ve_faas.py +754 -0
  89. veadk/integrations/ve_faas/ve_faas_utils.py +408 -0
  90. veadk/integrations/ve_faas/web_template/cookiecutter.json +20 -0
  91. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/__init__.py +13 -0
  92. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/clean.py +23 -0
  93. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/config.yaml.example +2 -0
  94. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/deploy.py +44 -0
  95. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/Dockerfile +23 -0
  96. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/app.py +123 -0
  97. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/init_db.py +46 -0
  98. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/models.py +36 -0
  99. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/requirements.txt +4 -0
  100. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/run.sh +21 -0
  101. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/static/css/style.css +368 -0
  102. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/static/js/admin.js +0 -0
  103. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/admin/dashboard.html +21 -0
  104. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/admin/edit_post.html +24 -0
  105. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/admin/login.html +21 -0
  106. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/admin/posts.html +53 -0
  107. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/base.html +45 -0
  108. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/index.html +29 -0
  109. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/post.html +14 -0
  110. veadk/integrations/ve_identity/__init__.py +110 -0
  111. veadk/integrations/ve_identity/auth_config.py +261 -0
  112. veadk/integrations/ve_identity/auth_mixins.py +650 -0
  113. veadk/integrations/ve_identity/auth_processor.py +385 -0
  114. veadk/integrations/ve_identity/function_tool.py +158 -0
  115. veadk/integrations/ve_identity/identity_client.py +864 -0
  116. veadk/integrations/ve_identity/mcp_tool.py +181 -0
  117. veadk/integrations/ve_identity/mcp_toolset.py +431 -0
  118. veadk/integrations/ve_identity/models.py +228 -0
  119. veadk/integrations/ve_identity/token_manager.py +188 -0
  120. veadk/integrations/ve_identity/utils.py +151 -0
  121. veadk/integrations/ve_prompt_pilot/__init__.py +13 -0
  122. veadk/integrations/ve_prompt_pilot/ve_prompt_pilot.py +85 -0
  123. veadk/integrations/ve_tls/__init__.py +13 -0
  124. veadk/integrations/ve_tls/utils.py +116 -0
  125. veadk/integrations/ve_tls/ve_tls.py +212 -0
  126. veadk/integrations/ve_tos/ve_tos.py +710 -0
  127. veadk/integrations/ve_viking_db_memory/__init__.py +13 -0
  128. veadk/integrations/ve_viking_db_memory/ve_viking_db_memory.py +308 -0
  129. veadk/knowledgebase/__init__.py +17 -0
  130. veadk/knowledgebase/backends/__init__.py +13 -0
  131. veadk/knowledgebase/backends/base_backend.py +72 -0
  132. veadk/knowledgebase/backends/in_memory_backend.py +91 -0
  133. veadk/knowledgebase/backends/opensearch_backend.py +162 -0
  134. veadk/knowledgebase/backends/redis_backend.py +172 -0
  135. veadk/knowledgebase/backends/utils.py +92 -0
  136. veadk/knowledgebase/backends/vikingdb_knowledge_backend.py +608 -0
  137. veadk/knowledgebase/entry.py +25 -0
  138. veadk/knowledgebase/knowledgebase.py +307 -0
  139. veadk/memory/__init__.py +35 -0
  140. veadk/memory/long_term_memory.py +365 -0
  141. veadk/memory/long_term_memory_backends/__init__.py +13 -0
  142. veadk/memory/long_term_memory_backends/base_backend.py +35 -0
  143. veadk/memory/long_term_memory_backends/in_memory_backend.py +67 -0
  144. veadk/memory/long_term_memory_backends/mem0_backend.py +155 -0
  145. veadk/memory/long_term_memory_backends/opensearch_backend.py +124 -0
  146. veadk/memory/long_term_memory_backends/redis_backend.py +140 -0
  147. veadk/memory/long_term_memory_backends/vikingdb_memory_backend.py +189 -0
  148. veadk/memory/short_term_memory.py +252 -0
  149. veadk/memory/short_term_memory_backends/__init__.py +13 -0
  150. veadk/memory/short_term_memory_backends/base_backend.py +31 -0
  151. veadk/memory/short_term_memory_backends/mysql_backend.py +49 -0
  152. veadk/memory/short_term_memory_backends/postgresql_backend.py +49 -0
  153. veadk/memory/short_term_memory_backends/sqlite_backend.py +55 -0
  154. veadk/memory/short_term_memory_processor.py +100 -0
  155. veadk/processors/__init__.py +26 -0
  156. veadk/processors/base_run_processor.py +120 -0
  157. veadk/prompts/__init__.py +13 -0
  158. veadk/prompts/agent_default_prompt.py +30 -0
  159. veadk/prompts/prompt_evaluator.py +20 -0
  160. veadk/prompts/prompt_memory_processor.py +55 -0
  161. veadk/prompts/prompt_optimization.py +150 -0
  162. veadk/runner.py +732 -0
  163. veadk/tools/__init__.py +13 -0
  164. veadk/tools/builtin_tools/__init__.py +13 -0
  165. veadk/tools/builtin_tools/agent_authorization.py +94 -0
  166. veadk/tools/builtin_tools/generate_image.py +23 -0
  167. veadk/tools/builtin_tools/image_edit.py +300 -0
  168. veadk/tools/builtin_tools/image_generate.py +446 -0
  169. veadk/tools/builtin_tools/lark.py +67 -0
  170. veadk/tools/builtin_tools/las.py +24 -0
  171. veadk/tools/builtin_tools/link_reader.py +66 -0
  172. veadk/tools/builtin_tools/llm_shield.py +381 -0
  173. veadk/tools/builtin_tools/load_knowledgebase.py +97 -0
  174. veadk/tools/builtin_tools/mcp_router.py +29 -0
  175. veadk/tools/builtin_tools/run_code.py +113 -0
  176. veadk/tools/builtin_tools/tts.py +253 -0
  177. veadk/tools/builtin_tools/vesearch.py +49 -0
  178. veadk/tools/builtin_tools/video_generate.py +363 -0
  179. veadk/tools/builtin_tools/web_scraper.py +76 -0
  180. veadk/tools/builtin_tools/web_search.py +83 -0
  181. veadk/tools/demo_tools.py +58 -0
  182. veadk/tools/load_knowledgebase_tool.py +149 -0
  183. veadk/tools/sandbox/__init__.py +13 -0
  184. veadk/tools/sandbox/browser_sandbox.py +37 -0
  185. veadk/tools/sandbox/code_sandbox.py +40 -0
  186. veadk/tools/sandbox/computer_sandbox.py +34 -0
  187. veadk/tracing/__init__.py +13 -0
  188. veadk/tracing/base_tracer.py +58 -0
  189. veadk/tracing/telemetry/__init__.py +13 -0
  190. veadk/tracing/telemetry/attributes/attributes.py +29 -0
  191. veadk/tracing/telemetry/attributes/extractors/common_attributes_extractors.py +180 -0
  192. veadk/tracing/telemetry/attributes/extractors/llm_attributes_extractors.py +858 -0
  193. veadk/tracing/telemetry/attributes/extractors/tool_attributes_extractors.py +152 -0
  194. veadk/tracing/telemetry/attributes/extractors/types.py +164 -0
  195. veadk/tracing/telemetry/exporters/__init__.py +13 -0
  196. veadk/tracing/telemetry/exporters/apmplus_exporter.py +558 -0
  197. veadk/tracing/telemetry/exporters/base_exporter.py +39 -0
  198. veadk/tracing/telemetry/exporters/cozeloop_exporter.py +129 -0
  199. veadk/tracing/telemetry/exporters/inmemory_exporter.py +248 -0
  200. veadk/tracing/telemetry/exporters/tls_exporter.py +139 -0
  201. veadk/tracing/telemetry/opentelemetry_tracer.py +320 -0
  202. veadk/tracing/telemetry/telemetry.py +411 -0
  203. veadk/types.py +47 -0
  204. veadk/utils/__init__.py +13 -0
  205. veadk/utils/audio_manager.py +95 -0
  206. veadk/utils/auth.py +294 -0
  207. veadk/utils/logger.py +59 -0
  208. veadk/utils/mcp_utils.py +44 -0
  209. veadk/utils/misc.py +184 -0
  210. veadk/utils/patches.py +101 -0
  211. veadk/utils/volcengine_sign.py +205 -0
  212. veadk/version.py +15 -0
  213. veadk_python-0.2.27.dist-info/METADATA +373 -0
  214. veadk_python-0.2.27.dist-info/RECORD +218 -0
  215. veadk_python-0.2.27.dist-info/WHEEL +5 -0
  216. veadk_python-0.2.27.dist-info/entry_points.txt +2 -0
  217. veadk_python-0.2.27.dist-info/licenses/LICENSE +201 -0
  218. veadk_python-0.2.27.dist-info/top_level.txt +1 -0
veadk/__init__.py ADDED
@@ -0,0 +1,37 @@
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 typing import TYPE_CHECKING
16
+
17
+ from veadk.version import VERSION
18
+
19
+ if TYPE_CHECKING:
20
+ from veadk.agent import Agent
21
+ from veadk.runner import Runner
22
+
23
+
24
+ # Lazy loading for `Agent` class
25
+ def __getattr__(name):
26
+ if name == "Agent":
27
+ from veadk.agent import Agent
28
+
29
+ return Agent
30
+ if name == "Runner":
31
+ from veadk.runner import Runner
32
+
33
+ return Runner
34
+ raise AttributeError(f"module 'veadk' has no attribute '{name}'")
35
+
36
+
37
+ __all__ = ["Agent", "Runner", "VERSION"]
veadk/a2a/__init__.py ADDED
@@ -0,0 +1,13 @@
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.
@@ -0,0 +1,45 @@
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 a2a.types import AgentCapabilities, AgentCard, AgentProvider, AgentSkill
16
+
17
+ from veadk import Agent
18
+ from veadk.version import VERSION
19
+
20
+
21
+ def get_agent_card(
22
+ agent: Agent, url: str, version: str = VERSION, provider: str = "veadk"
23
+ ) -> AgentCard:
24
+ agent_provider = AgentProvider(organization=provider, url="")
25
+ agent_capabilities = AgentCapabilities()
26
+ agent_skills = [
27
+ AgentSkill(
28
+ id="0",
29
+ name="chat",
30
+ description="Basically chat with user.",
31
+ tags=["chat", "talk"],
32
+ )
33
+ ]
34
+ agent_card = AgentCard(
35
+ capabilities=agent_capabilities,
36
+ description=agent.description,
37
+ name=agent.name,
38
+ defaultInputModes=["text"],
39
+ defaultOutputModes=["text"],
40
+ provider=agent_provider,
41
+ skills=agent_skills,
42
+ url=url,
43
+ version=version,
44
+ )
45
+ return agent_card
@@ -0,0 +1,390 @@
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
+ import json
16
+ import functools
17
+ from typing import AsyncGenerator, Literal, Optional
18
+
19
+ from a2a.client.base_client import BaseClient
20
+ import httpx
21
+ import requests
22
+ from a2a.types import AgentCard
23
+ from google.adk.agents.remote_a2a_agent import RemoteA2aAgent
24
+
25
+ from veadk.integrations.ve_identity.utils import generate_headers
26
+ from veadk.utils.auth import VE_TIP_TOKEN_CREDENTIAL_KEY, VE_TIP_TOKEN_HEADER
27
+ from veadk.utils.logger import get_logger
28
+ from google.adk.utils.context_utils import Aclosing
29
+ from google.adk.events.event import Event
30
+ from google.adk.agents.invocation_context import InvocationContext
31
+
32
+
33
+ logger = get_logger(__name__)
34
+
35
+ AGENT_CARD_WELL_KNOWN_PATH = "/.well-known/agent-card.json"
36
+
37
+
38
+ def _convert_agent_card_dict_to_obj(agent_card_dict: dict) -> AgentCard:
39
+ agent_card_json_str = json.dumps(agent_card_dict, ensure_ascii=False, indent=2)
40
+ agent_card_object = AgentCard.model_validate_json(str(agent_card_json_str))
41
+ return agent_card_object
42
+
43
+
44
+ class RemoteVeAgent(RemoteA2aAgent):
45
+ """Connect to a remote agent on the VeFaaS platform.
46
+
47
+ This class provides an interface to remotely connect with an agent deployed on the
48
+ VeFaaS platform. It automatically fetches the agent card (metadata) and configures
49
+ an HTTP client for secure communication.
50
+
51
+ The class extends `RemoteA2aAgent` to provide compatibility with the A2A
52
+ (Agent-to-Agent) communication layer.
53
+
54
+ This constructor handles agent discovery and HTTP client setup. It determines the
55
+ agent's URL, fetches its metadata (`agent_card`), and prepares an
56
+ `httpx.AsyncClient` for subsequent communication. You can either provide a URL
57
+ directly, or pass a pre-configured `httpx.AsyncClient` with a `base_url`.
58
+
59
+ Authentication can be handled via a bearer token in the HTTP header or via a
60
+ query string parameter. If a custom `httpx_client` is provided, authentication
61
+ details will be added to it.
62
+
63
+ Attributes:
64
+ name (str):
65
+ A unique name identifying this remote agent instance.
66
+ url (Optional[str]):
67
+ The base URL of the remote agent. This is optional if an `httpx_client`
68
+ with a configured `base_url` is provided. If both are given, they must
69
+ not conflict.
70
+ auth_token (Optional[str]):
71
+ Optional authentication token used for secure access during initialization.
72
+ If not provided, the agent will be accessed without authentication.
73
+ Note: For runtime authentication, use the credential service in InvocationContext.
74
+ auth_method (Literal["header", "querystring"] | None):
75
+ The method of attaching the authentication token at runtime.
76
+ - `"header"`: Token is retrieved from credential service and passed via HTTP `Authorization` header.
77
+ - `"querystring"`: Token is retrieved from credential service and passed as a query parameter.
78
+ - `None`: No runtime authentication injection (default).
79
+ The credential is loaded from `InvocationContext.credential_service` using the
80
+ app_name and user_id from the context.
81
+ httpx_client (Optional[httpx.AsyncClient]):
82
+ An optional, pre-configured `httpx.AsyncClient` to use for communication.
83
+ This allows for client sharing and advanced configurations (e.g., proxies).
84
+ If its `base_url` is set, it will be used as the agent's location.
85
+
86
+ Raises:
87
+ ValueError:
88
+ - If `url` and `httpx_client.base_url` are both provided and conflict.
89
+ - If neither `url` nor an `httpx_client` with a `base_url` is provided.
90
+ - If an unsupported `auth_method` is provided when `auth_token` is set.
91
+ requests.RequestException:
92
+ If fetching the agent card from the remote URL fails.
93
+
94
+ Examples:
95
+ ```python
96
+ # Example 1: Connect using a URL (no authentication)
97
+ agent = RemoteVeAgent(
98
+ name="public_agent",
99
+ url="https://vefaas.example.com/agents/public"
100
+ )
101
+
102
+ # Example 2: Using static Bearer token in header for initialization
103
+ agent = RemoteVeAgent(
104
+ name="secured_agent",
105
+ url="https://vefaas.example.com/agents/secure",
106
+ auth_token="my_secret_token",
107
+ auth_method="header"
108
+ )
109
+
110
+ # Example 3: Using runtime authentication with credential service
111
+ # The auth token will be automatically injected from InvocationContext.credential_service
112
+ agent = RemoteVeAgent(
113
+ name="dynamic_auth_agent",
114
+ url="https://vefaas.example.com/agents/secure",
115
+ auth_method="header" # Will load credential at runtime
116
+ )
117
+
118
+ # Example 4: Using a pre-configured httpx_client
119
+ import httpx
120
+ client = httpx.AsyncClient(
121
+ base_url="https://vefaas.example.com/agents/query",
122
+ timeout=600
123
+ )
124
+ agent = RemoteVeAgent(
125
+ name="query_agent",
126
+ auth_method="querystring", # Will load credential at runtime
127
+ httpx_client=client
128
+ )
129
+ ```
130
+ """
131
+
132
+ auth_method: Literal["header", "querystring"] | None = None
133
+
134
+ def __init__(
135
+ self,
136
+ name: str,
137
+ url: Optional[str] = None,
138
+ auth_token: Optional[str] = None,
139
+ auth_method: Literal["header", "querystring"] | None = None,
140
+ httpx_client: Optional[httpx.AsyncClient] = None,
141
+ ):
142
+ # Determine the effective URL for the agent and handle conflicts.
143
+ effective_url = url
144
+ if httpx_client and httpx_client.base_url:
145
+ client_url_str = str(httpx_client.base_url).rstrip("/")
146
+ if url and url.rstrip("/") != client_url_str:
147
+ raise ValueError(
148
+ f"The `url` parameter ('{url}') conflicts with the `base_url` of the provided "
149
+ f"httpx_client ('{client_url_str}'). Please provide only one or ensure they match."
150
+ )
151
+ effective_url = client_url_str
152
+
153
+ if not effective_url:
154
+ raise ValueError(
155
+ "Could not determine agent URL. Please provide the `url` parameter or an `httpx_client` with a configured `base_url`."
156
+ )
157
+
158
+ req_headers = {}
159
+ req_params = {}
160
+
161
+ if auth_token:
162
+ if auth_method == "header":
163
+ req_headers = {"Authorization": f"Bearer {auth_token}"}
164
+ elif auth_method == "querystring":
165
+ req_params = {"token": auth_token}
166
+ elif auth_method:
167
+ raise ValueError(
168
+ f"Unsupported auth method {auth_method}, use `header` or `querystring` instead."
169
+ )
170
+
171
+ agent_card_dict = requests.get(
172
+ effective_url + AGENT_CARD_WELL_KNOWN_PATH,
173
+ headers=req_headers,
174
+ params=req_params,
175
+ ).json()
176
+ # replace agent_card_url with actual host
177
+ agent_card_dict["url"] = effective_url
178
+
179
+ agent_card_object = _convert_agent_card_dict_to_obj(agent_card_dict)
180
+
181
+ logger.debug(f"Agent card of {name}: {agent_card_object}")
182
+
183
+ client_was_provided = httpx_client is not None
184
+ client_to_use = httpx_client
185
+
186
+ if client_was_provided:
187
+ # If a client was provided, update it with auth info
188
+ if auth_token:
189
+ if auth_method == "header":
190
+ client_to_use.headers.update(req_headers)
191
+ elif auth_method == "querystring":
192
+ new_params = dict(client_to_use.params)
193
+ new_params.update(req_params)
194
+ client_to_use.params = new_params
195
+ else:
196
+ # If no client was provided, create a new one with auth info
197
+ if auth_token:
198
+ if auth_method == "header":
199
+ client_to_use = httpx.AsyncClient(
200
+ base_url=effective_url, headers=req_headers, timeout=600
201
+ )
202
+ elif auth_method == "querystring":
203
+ client_to_use = httpx.AsyncClient(
204
+ base_url=effective_url, params=req_params, timeout=600
205
+ )
206
+ else: # No auth, no client provided
207
+ client_to_use = httpx.AsyncClient(base_url=effective_url, timeout=600)
208
+
209
+ super().__init__(
210
+ name=name, agent_card=agent_card_object, httpx_client=client_to_use
211
+ )
212
+
213
+ # The parent class sets _httpx_client_needs_cleanup based on whether
214
+ # the httpx_client it received was None. Since we always pass a
215
+ # client (either the user's or one we create), it will always set
216
+ # it to False. We must override this to ensure clients we create
217
+ # are properly cleaned up.
218
+ if not client_was_provided:
219
+ self._httpx_client_needs_cleanup = True
220
+
221
+ # Set auth_method if provided
222
+ if auth_method:
223
+ self.auth_method = auth_method
224
+
225
+ # Wrap _run_async_impl with pre-run hook to ensure initialization
226
+ # and authentication logic always executes, even if users override _run_async_impl
227
+ self._wrap_run_async_impl()
228
+
229
+ def _wrap_run_async_impl(self) -> None:
230
+ """Wrap _run_async_impl with a decorator that ensures pre-run logic executes.
231
+
232
+ This method wraps the _run_async_impl method with a decorator that:
233
+ 1. Executes _pre_run before the actual implementation
234
+ 2. Handles errors from _pre_run and yields error events
235
+ 3. Ensures the wrapper works even if users override _run_async_impl
236
+
237
+ The wrapper is applied by replacing the bound method on the instance.
238
+ """
239
+ # Store the original _run_async_impl method
240
+ original_run_async_impl = self._run_async_impl
241
+
242
+ @functools.wraps(original_run_async_impl)
243
+ async def wrapped_run_async_impl(
244
+ ctx: InvocationContext,
245
+ ) -> AsyncGenerator[Event, None]:
246
+ """Wrapped version of _run_async_impl with pre-run hook."""
247
+ # Execute pre-run initialization
248
+ try:
249
+ await self._pre_run(ctx)
250
+ except Exception as e:
251
+ yield Event(
252
+ author=self.name,
253
+ error_message=f"Failed to initialize remote A2A agent: {e}",
254
+ invocation_id=ctx.invocation_id,
255
+ branch=ctx.branch,
256
+ )
257
+ return
258
+
259
+ # Call the original (or overridden) _run_async_impl
260
+ async with Aclosing(original_run_async_impl(ctx)) as agen:
261
+ async for event in agen:
262
+ yield event
263
+
264
+ # Replace the instance method with the wrapped version
265
+ self._run_async_impl = wrapped_run_async_impl
266
+
267
+ async def _pre_run(self, ctx: InvocationContext) -> None:
268
+ """Pre-run initialization and authentication setup.
269
+
270
+ This method is called before the actual agent execution to:
271
+ 1. Ensure the agent is resolved (agent card fetched, client initialized)
272
+ 2. Inject authentication token from credential service if available
273
+
274
+ This method is separated from _run_async_impl to ensure these critical
275
+ initialization steps are always executed, even if users override _run_async_impl.
276
+
277
+ Args:
278
+ ctx: Invocation context containing session and user information
279
+
280
+ Raises:
281
+ Exception: If agent initialization fails
282
+ """
283
+ # Ensure agent is resolved
284
+ await self._ensure_resolved()
285
+
286
+ # Inject auth token if credential service is available
287
+ await self._inject_auth_token(ctx)
288
+
289
+ async def _inject_auth_token(self, ctx: InvocationContext) -> None:
290
+ """Inject authentication token from credential service into the HTTP client.
291
+
292
+ This method retrieves the authentication token from the credential service
293
+ in the InvocationContext and updates the HTTP client headers or query params
294
+ based on the configured auth_method.
295
+
296
+ Args:
297
+ ctx: Invocation context containing credential service and user information
298
+ """
299
+ # Skip if no credential service in context
300
+ if not ctx.credential_service:
301
+ logger.debug(
302
+ "No credential service in InvocationContext, skipping auth token injection"
303
+ )
304
+ return
305
+
306
+ # Skip if client is not initialized or not a BaseClient
307
+ if not hasattr(self, "_a2a_client") or not isinstance(
308
+ self._a2a_client, BaseClient
309
+ ):
310
+ logger.debug(
311
+ "A2A client not initialized or not a BaseClient, skipping auth token injection"
312
+ )
313
+ return
314
+
315
+ # Skip if transport is not available
316
+ if not hasattr(self._a2a_client, "_transport"):
317
+ logger.debug(
318
+ "A2A client transport not available, skipping auth token injection"
319
+ )
320
+ return
321
+
322
+ # Skip if httpx_client is not available
323
+ if not hasattr(self._a2a_client._transport, "httpx_client"):
324
+ logger.debug(
325
+ "A2A client httpx_client not available, skipping auth token injection"
326
+ )
327
+ return
328
+
329
+ try:
330
+ from veadk.utils.auth import build_auth_config
331
+ from google.adk.agents.callback_context import CallbackContext
332
+
333
+ # Inject TIP token via header
334
+ workload_auth_config = build_auth_config(
335
+ auth_method="apikey",
336
+ credential_key=VE_TIP_TOKEN_CREDENTIAL_KEY,
337
+ header_name=VE_TIP_TOKEN_HEADER,
338
+ )
339
+
340
+ tip_credential = await ctx.credential_service.load_credential(
341
+ auth_config=workload_auth_config,
342
+ callback_context=CallbackContext(ctx),
343
+ )
344
+
345
+ if tip_credential:
346
+ self._a2a_client._transport.httpx_client.headers.update(
347
+ {VE_TIP_TOKEN_HEADER: tip_credential.api_key}
348
+ )
349
+ logger.debug(
350
+ f"Injected TIP token via header for app={ctx.app_name}, user={ctx.user_id}"
351
+ )
352
+
353
+ # Build auth config based on auth_method
354
+ auth_config = build_auth_config(
355
+ credential_key="inbound_auth",
356
+ auth_method=self.auth_method or "header",
357
+ header_scheme="bearer",
358
+ )
359
+
360
+ # Load credential from credential service
361
+ credential = await ctx.credential_service.load_credential(
362
+ auth_config=auth_config,
363
+ callback_context=CallbackContext(ctx),
364
+ )
365
+
366
+ if not credential:
367
+ logger.debug(
368
+ f"No credential loaded, skipping auth token injection for app={ctx.app_name}, user={ctx.user_id}"
369
+ )
370
+ return
371
+
372
+ # Inject credential based on auth_method
373
+ if self.auth_method == "querystring":
374
+ # Extract API key
375
+ api_key = credential.api_key
376
+ new_params = dict(self._a2a_client._transport.httpx_client.params)
377
+ new_params.update({"token": api_key})
378
+ self._a2a_client._transport.httpx_client.params = new_params
379
+ logger.debug(
380
+ f"Injected auth token via querystring for app={ctx.app_name}, user={ctx.user_id}"
381
+ )
382
+ else:
383
+ if headers := generate_headers(credential):
384
+ self._a2a_client._transport.httpx_client.headers.update(headers)
385
+ logger.debug(
386
+ f"Injected auth token via header for app={ctx.app_name}, user={ctx.user_id}"
387
+ )
388
+
389
+ except Exception as e:
390
+ logger.warning(f"Failed to inject auth token: {e}", exc_info=True)
@@ -0,0 +1,13 @@
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.
@@ -0,0 +1,170 @@
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
+ from typing import Literal, Optional, Union
17
+
18
+ from a2a.types import AgentCard
19
+ from google.adk.agents import BaseAgent
20
+ from starlette.applications import Starlette
21
+ from google.adk.artifacts.in_memory_artifact_service import InMemoryArtifactService
22
+ from google.adk.sessions.in_memory_session_service import InMemorySessionService
23
+ from google.adk.memory.in_memory_memory_service import InMemoryMemoryService
24
+ from google.adk.a2a.utils.agent_to_a2a import to_a2a as google_adk_to_a2a
25
+ from veadk import Runner
26
+ from veadk.a2a.ve_middlewares import build_a2a_auth_middleware
27
+ from veadk.auth.ve_credential_service import VeCredentialService
28
+ from veadk.consts import DEFAULT_AGENT_NAME
29
+
30
+
31
+ def to_a2a(
32
+ agent: BaseAgent,
33
+ *,
34
+ host: str = "localhost",
35
+ port: int = 8000,
36
+ protocol: str = "http",
37
+ agent_card: Optional[Union[AgentCard, str]] = None,
38
+ runner: Optional[Runner] = None,
39
+ enable_auth: bool = False,
40
+ auth_method: Literal["header", "querystring"] = "header",
41
+ ) -> Starlette:
42
+ """Convert an ADK agent to a A2A Starlette application with optional VeADK enhancements.
43
+
44
+ This function wraps Google ADK's to_a2a utility and optionally adds:
45
+ - VeCredentialService for authentication management
46
+ - A2A authentication middleware for token validation
47
+
48
+ Args:
49
+ agent: The ADK agent to convert to A2A server
50
+ host: The host for the A2A RPC URL (default: "localhost")
51
+ port: The port for the A2A RPC URL (default: 8000)
52
+ protocol: The protocol for the A2A RPC URL (default: "http")
53
+ agent_card: Optional pre-built AgentCard object or path to agent card
54
+ JSON. If not provided, will be built automatically from the
55
+ agent.
56
+ runner: Optional pre-built Runner object. If not provided, a default
57
+ runner will be created using in-memory services.
58
+ When enable_auth=True:
59
+ - If runner is provided and has a credential_service, it must be
60
+ a VeCredentialService instance (raises TypeError otherwise)
61
+ - If runner is provided without credential_service, a new
62
+ VeCredentialService will be created and set
63
+ - If runner is not provided, a new runner with VeCredentialService
64
+ will be created
65
+ auth_method: Authentication method for A2A requests (only used when
66
+ enable_auth=True). Options:
67
+ - "header": Extract token from Authorization header (default)
68
+ - "querystring": Extract token from query parameter
69
+ enable_auth: Whether to enable VeADK authentication features.
70
+ When True, enables credential service and auth middleware.
71
+ When False, uses standard Google ADK behavior.
72
+ Default: False
73
+
74
+ Returns:
75
+ A Starlette application that can be run with uvicorn
76
+
77
+ Raises:
78
+ TypeError: If enable_auth=True and runner has a credential_service
79
+ that is not a VeCredentialService instance
80
+
81
+ Example:
82
+ Basic usage (without VeADK auth):
83
+ ```python
84
+ from veadk import Agent
85
+ from veadk.a2a.utils.agent_to_a2a import to_a2a
86
+
87
+ agent = Agent(name="my_agent", tools=[...])
88
+ app = to_a2a(agent, host="localhost", port=8000)
89
+ # Run with: uvicorn module:app --host localhost --port 8000
90
+ ```
91
+
92
+ With VeADK authentication enabled:
93
+ ```python
94
+ app = to_a2a(agent, enable_auth=True)
95
+ ```
96
+
97
+ With custom runner and VeADK auth:
98
+ ```python
99
+ from veadk import Agent, Runner
100
+ from veadk.memory.short_term_memory import ShortTermMemory
101
+ from veadk.auth.ve_credential_service import VeCredentialService
102
+
103
+ agent = Agent(name="my_agent")
104
+ runner = Runner(
105
+ agent=agent,
106
+ short_term_memory=ShortTermMemory(),
107
+ app_name="my_app",
108
+ credential_service=VeCredentialService() # Optional
109
+ )
110
+ app = to_a2a(agent, runner=runner, enable_auth=True)
111
+ ```
112
+
113
+ With querystring authentication:
114
+ ```python
115
+ app = to_a2a(agent, enable_auth=True, auth_method="querystring")
116
+ ```
117
+ """
118
+ app_name = agent.name or DEFAULT_AGENT_NAME
119
+ middleware = None # May need support multiple middlewares in the future
120
+
121
+ # Handle VeADK authentication setup
122
+ if enable_auth:
123
+ # Create credential service if not provided
124
+ credential_service = VeCredentialService()
125
+ if runner is not None:
126
+ # Check if runner has credential_service
127
+ if runner.credential_service is not None:
128
+ # Validate that it's a VeCredentialService
129
+ if not isinstance(runner.credential_service, VeCredentialService):
130
+ raise TypeError(
131
+ f"When enable_auth=True, runner.credential_service must be "
132
+ f"a VeCredentialService instance, got {type(runner.credential_service).__name__}"
133
+ )
134
+ # Use existing credential service
135
+ credential_service = runner.credential_service
136
+ else:
137
+ # Add credential_service to runner
138
+ runner.credential_service = credential_service
139
+ else:
140
+ # Create runner with credential_service
141
+ runner = Runner(
142
+ app_name=app_name,
143
+ agent=agent,
144
+ artifact_service=InMemoryArtifactService(),
145
+ session_service=InMemorySessionService(),
146
+ memory_service=InMemoryMemoryService(),
147
+ credential_service=credential_service,
148
+ )
149
+
150
+ middleware = build_a2a_auth_middleware(
151
+ app_name=app_name,
152
+ credential_service=credential_service,
153
+ auth_method=auth_method,
154
+ )
155
+
156
+ # Convert agent to A2A Starlette app using Google ADK utility
157
+ app: Starlette = google_adk_to_a2a(
158
+ agent=agent,
159
+ host=host,
160
+ port=port,
161
+ protocol=protocol,
162
+ agent_card=agent_card,
163
+ runner=runner,
164
+ )
165
+
166
+ # Add VeADK authentication middleware only if enabled
167
+ if middleware:
168
+ app.add_middleware(middleware)
169
+
170
+ return app