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
@@ -0,0 +1,93 @@
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.server.apps.jsonrpc.fastapi_app import A2AFastAPIApplication
16
+ from a2a.server.request_handlers.default_request_handler import DefaultRequestHandler
17
+ from a2a.server.tasks.inmemory_task_store import InMemoryTaskStore
18
+ from fastapi import FastAPI
19
+
20
+ from veadk import Agent
21
+ from veadk.a2a.agent_card import get_agent_card
22
+ from veadk.runner import Runner
23
+ from veadk.memory.short_term_memory import ShortTermMemory
24
+
25
+ from google.adk.a2a.executor.a2a_agent_executor import A2aAgentExecutor
26
+ from google.adk.auth.credential_service.base_credential_service import (
27
+ BaseCredentialService,
28
+ )
29
+
30
+
31
+ class VeA2AServer:
32
+ def __init__(
33
+ self,
34
+ agent: Agent,
35
+ url: str,
36
+ app_name: str,
37
+ short_term_memory: ShortTermMemory,
38
+ credential_service: BaseCredentialService | None = None,
39
+ ):
40
+ self.agent_card = get_agent_card(agent, url)
41
+
42
+ self.agent_executor = A2aAgentExecutor(
43
+ runner=Runner(
44
+ agent=agent,
45
+ app_name=app_name,
46
+ short_term_memory=short_term_memory,
47
+ credential_service=credential_service,
48
+ )
49
+ )
50
+
51
+ self.task_store = InMemoryTaskStore()
52
+
53
+ self.request_handler = DefaultRequestHandler(
54
+ agent_executor=self.agent_executor, task_store=self.task_store
55
+ )
56
+
57
+ def build(self) -> FastAPI:
58
+ app_application = A2AFastAPIApplication(
59
+ agent_card=self.agent_card,
60
+ http_handler=self.request_handler,
61
+ )
62
+ app = app_application.build() # build routes
63
+
64
+ return app
65
+
66
+
67
+ def init_app(
68
+ server_url: str,
69
+ app_name: str,
70
+ agent: Agent,
71
+ short_term_memory: ShortTermMemory,
72
+ credential_service: BaseCredentialService | None = None,
73
+ ) -> FastAPI:
74
+ """Init the fastapi application in terms of VeADK agent.
75
+
76
+ Args:
77
+ server_url: str, the url of the server
78
+ app_name: str, the name of the app
79
+ agent: Agent, the agent of the app
80
+ short_term_memory: ShortTermMemory, the short term memory of the app
81
+
82
+ Returns:
83
+ FastAPI, the fastapi app
84
+ """
85
+
86
+ server = VeA2AServer(
87
+ agent=agent,
88
+ url=server_url,
89
+ app_name=app_name,
90
+ short_term_memory=short_term_memory,
91
+ credential_service=credential_service,
92
+ )
93
+ return server.build()
@@ -0,0 +1,78 @@
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.server.agent_execution.agent_executor import AgentExecutor
16
+ from a2a.server.agent_execution.context import RequestContext
17
+ from a2a.server.events.event_queue import EventQueue
18
+ from a2a.utils import new_agent_text_message
19
+ from typing_extensions import override
20
+
21
+ from veadk import Agent
22
+ from veadk.memory.short_term_memory import ShortTermMemory
23
+ from veadk.runner import Runner
24
+ from veadk.utils.logger import get_logger
25
+
26
+ logger = get_logger(__name__)
27
+
28
+
29
+ class VeAgentExecutor(AgentExecutor):
30
+ def __init__(self, app_name: str, agent: Agent, short_term_memory: ShortTermMemory):
31
+ super().__init__()
32
+ self.app_name = app_name
33
+ self.agent = agent
34
+ self.short_term_memory = short_term_memory
35
+
36
+ self.runner = Runner(
37
+ agent=self.agent,
38
+ short_term_memory=self.short_term_memory,
39
+ app_name=app_name,
40
+ user_id="", # waiting for `execute` change
41
+ )
42
+
43
+ @override
44
+ async def execute(self, context: RequestContext, event_queue: EventQueue) -> None:
45
+ # extract metadata
46
+ user_id = (
47
+ context.metadata["user_id"]
48
+ if "user_id" in context.metadata
49
+ else "unkonwn_user"
50
+ )
51
+ self.runner.user_id = user_id
52
+
53
+ session_id = (
54
+ context.metadata["session_id"]
55
+ if "session_id" in context.metadata
56
+ else "unkonwn_session"
57
+ )
58
+
59
+ # process user input
60
+ user_input = context.get_user_input()
61
+
62
+ logger.debug(
63
+ f"Request: user_id: {user_id}, session_id: {session_id}, user_input: {user_input}"
64
+ )
65
+
66
+ # running
67
+ final_output = await self.runner.run(
68
+ messages=user_input,
69
+ session_id=session_id,
70
+ )
71
+
72
+ logger.debug(f"Final output: {final_output}")
73
+
74
+ await event_queue.enqueue_event(new_agent_text_message(final_output))
75
+
76
+ @override
77
+ async def cancel(self, context: RequestContext, event_queue: EventQueue) -> None:
78
+ return None
@@ -0,0 +1,313 @@
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
+ """A2A Authentication Middleware for FastAPI/Starlette.
16
+
17
+ This module provides middleware for extracting authentication credentials
18
+ from HTTP requests and storing them in the credential service.
19
+ """
20
+
21
+ import logging
22
+ from typing import Callable, Literal, Optional
23
+
24
+ from starlette.middleware.base import BaseHTTPMiddleware
25
+ from starlette.requests import Request
26
+ from starlette.responses import Response
27
+ from volcenginesdkcore.rest import ApiException
28
+
29
+
30
+ from veadk.auth.ve_credential_service import VeCredentialService
31
+ from veadk.utils.auth import (
32
+ extract_delegation_chain_from_jwt,
33
+ build_auth_config,
34
+ VE_TIP_TOKEN_HEADER,
35
+ VE_TIP_TOKEN_CREDENTIAL_KEY,
36
+ )
37
+ from veadk.integrations.ve_identity import (
38
+ WorkloadToken,
39
+ IdentityClient,
40
+ get_default_identity_client,
41
+ )
42
+
43
+ logger = logging.getLogger(__name__)
44
+
45
+
46
+ class A2AAuthMiddleware(BaseHTTPMiddleware):
47
+ """Middleware to extract and store authentication credentials from requests.
48
+
49
+ This middleware:
50
+ 1. Extracts auth tokens from Authorization header or query string
51
+ 2. Parses JWT tokens to extract user_id and delegation chain
52
+ 3. Builds AuthConfig based on the authentication method
53
+ 4. Stores credentials in the credential service
54
+ 5. Extracts TIP token from X-Ve-TIP-Token header for trust propagation
55
+ 6. Exchanges TIP token for workload access token using IdentityClient
56
+ 7. Sets workload token in request.scope["auth"] for downstream use
57
+
58
+ Examples:
59
+ ```python
60
+ from fastapi import FastAPI
61
+ from veadk.a2a.ve_middlewares import build_a2a_auth_middleware
62
+ from veadk.auth.ve_credential_service import VeCredentialService
63
+
64
+ app = FastAPI()
65
+ credential_service = VeCredentialService()
66
+
67
+ # Add middleware with Authorization header support
68
+ app.add_middleware(
69
+ build_a2a_auth_middleware(
70
+ app_name="my_app",
71
+ credential_service=credential_service,
72
+ auth_method="header"
73
+ )
74
+ )
75
+
76
+ # Or with query string support
77
+ app.add_middleware(
78
+ build_a2a_auth_middleware(
79
+ app_name="my_app",
80
+ credential_service=credential_service,
81
+ auth_method="querystring",
82
+ token_param="token"
83
+ )
84
+ )
85
+ ```
86
+ """
87
+
88
+ def __init__(
89
+ self,
90
+ app,
91
+ app_name: str,
92
+ credential_service: VeCredentialService,
93
+ auth_method: Literal["header", "querystring"] = "header",
94
+ token_param: str = "token",
95
+ credential_key: str = "inbound_auth",
96
+ identity_client: Optional[IdentityClient] = None,
97
+ ):
98
+ """Initialize the middleware.
99
+
100
+ Args:
101
+ app: The ASGI application
102
+ app_name: Application name for credential storage
103
+ credential_service: Credential service to store credentials
104
+ auth_method: Authentication method - "header" or "querystring"
105
+ token_param: Query parameter name for token (when auth_method="querystring")
106
+ credential_key: Key to identify the credential in the store
107
+ identity_client: Optional IdentityClient for TIP token exchange.
108
+ If not provided, uses the global IdentityClient from VeIdentityConfig.
109
+ """
110
+ super().__init__(app)
111
+ self.app_name = app_name
112
+ self.credential_service = credential_service
113
+ self.auth_method = auth_method
114
+ self.token_param = token_param
115
+ self.credential_key = credential_key
116
+ self.identity_client = identity_client or get_default_identity_client()
117
+
118
+ async def dispatch(self, request: Request, call_next: Callable) -> Response:
119
+ """Process the request and extract authentication credentials.
120
+
121
+ This method:
122
+ 1. Extracts token from Authorization header or query string
123
+ 2. Parses JWT to get user_id and stores credentials
124
+ 3. Sets request.scope["user"] with SimpleUser instance
125
+ 4. Extracts TIP token from X-Ve-TIP-Token header
126
+ 5. Exchanges TIP token for workload token via IdentityClient
127
+ 6. Sets request.scope["auth"] with WorkloadToken object
128
+
129
+ Args:
130
+ request: The incoming HTTP request
131
+ call_next: The next middleware or route handler
132
+
133
+ Returns:
134
+ The HTTP response
135
+ """
136
+ from starlette.authentication import SimpleUser
137
+
138
+ token, has_prefix = self._extract_token(request)
139
+ user_id = None
140
+
141
+ if token:
142
+ user_id, _ = extract_delegation_chain_from_jwt(token)
143
+ if user_id:
144
+ # Build auth config based on authentication method
145
+ auth_config = build_auth_config(
146
+ token=token,
147
+ auth_method=self.auth_method,
148
+ credential_key=self.credential_key,
149
+ header_scheme="bearer" if has_prefix else None,
150
+ query_param_name=self.token_param,
151
+ )
152
+
153
+ await self.credential_service.set_credential(
154
+ app_name=self.app_name,
155
+ user_id=user_id,
156
+ credential_key=self.credential_key,
157
+ credential=auth_config.exchanged_auth_credential,
158
+ )
159
+
160
+ logger.debug(
161
+ f"Stored credential for app={self.app_name}, user={user_id}, "
162
+ f"method={self.auth_method}"
163
+ )
164
+
165
+ request.scope["user"] = SimpleUser(user_id)
166
+ else:
167
+ logger.warning("Failed to extract user_id from JWT token")
168
+
169
+ # Extract TIP token from X-Ve-TIP-Token header for trust propagation
170
+ tip_token = request.headers.get(VE_TIP_TOKEN_HEADER)
171
+
172
+ try:
173
+ workload_token: WorkloadToken = (
174
+ self.identity_client.get_workload_access_token(
175
+ user_token=tip_token, user_id=user_id
176
+ )
177
+ )
178
+ workload_auth_config = build_auth_config(
179
+ token=workload_token.workload_access_token,
180
+ auth_method="apikey",
181
+ credential_key=VE_TIP_TOKEN_CREDENTIAL_KEY,
182
+ header_name=VE_TIP_TOKEN_HEADER,
183
+ )
184
+
185
+ await self.credential_service.set_credential(
186
+ app_name=self.app_name,
187
+ user_id=user_id,
188
+ credential_key=VE_TIP_TOKEN_CREDENTIAL_KEY,
189
+ credential=workload_auth_config.exchanged_auth_credential,
190
+ )
191
+ except ApiException as e:
192
+ logger.warning(f"Failed to get workload token: {e.reason}")
193
+ workload_token = None
194
+ request.scope["auth"] = workload_token
195
+ # Continue processing the request
196
+ response = await call_next(request)
197
+ return response
198
+
199
+ def _extract_token(self, request: Request) -> tuple[Optional[str], bool]:
200
+ """Extract authentication token from the request.
201
+
202
+ Args:
203
+ request: The HTTP request
204
+
205
+ Returns:
206
+ The extracted token, or None if not found
207
+ """
208
+ has_prefix = False
209
+ token = None
210
+
211
+ if self.auth_method == "header":
212
+ # Extract from Authorization header
213
+ auth_header = request.headers.get("Authorization") or request.headers.get(
214
+ "authorization"
215
+ )
216
+ if auth_header:
217
+ # Strip "Bearer " prefix if present
218
+ if auth_header.lower().startswith("bearer "):
219
+ has_prefix = True
220
+ token = auth_header[7:]
221
+ else:
222
+ token = auth_header
223
+ else:
224
+ token = None
225
+ elif self.auth_method == "querystring":
226
+ # Extract from query string
227
+ token = request.query_params.get(self.token_param)
228
+
229
+ return token, has_prefix
230
+
231
+
232
+ def build_a2a_auth_middleware(
233
+ app_name: str,
234
+ credential_service: VeCredentialService,
235
+ auth_method: Literal["header", "querystring"] = "header",
236
+ token_param: str = "token",
237
+ credential_key: str = "inbound_auth",
238
+ identity_client: Optional[IdentityClient] = None,
239
+ ) -> type[A2AAuthMiddleware]:
240
+ """Build an A2A authentication middleware class.
241
+
242
+ This is a factory function that creates a middleware class with the
243
+ specified configuration. Use this with FastAPI's add_middleware().
244
+
245
+ The middleware extracts authentication tokens from incoming requests,
246
+ parses JWT delegation chains, stores credentials, and sets user information
247
+ in the request state for downstream handlers.
248
+
249
+ TIP Token Support:
250
+ The middleware will:
251
+ 1. Extract TIP token from X-Ve-TIP-Token header
252
+ 2. Exchange TIP token for workload token using IdentityClient
253
+ 3. Set WorkloadToken object in request.scope["auth"] for downstream use
254
+
255
+ If identity_client is not provided, uses the global IdentityClient
256
+ from VeIdentityConfig.
257
+
258
+ Args:
259
+ app_name: Application name for credential storage
260
+ credential_service: Credential service to store credentials
261
+ auth_method: Authentication method - "header" or "querystring"
262
+ token_param: Query parameter name for token (when auth_method="querystring")
263
+ credential_key: Key to identify the credential in the store
264
+ identity_client: Optional IdentityClient for TIP token exchange.
265
+ If not provided, uses the global IdentityClient from VeIdentityConfig.
266
+
267
+ Returns:
268
+ A configured middleware class
269
+
270
+ Request Attributes:
271
+ After successful authentication, the following attributes are set:
272
+ - request.scope["user"]: SimpleUser instance with the user_id from JWT
273
+ - request.scope["auth"]: WorkloadToken object containing workload_access_token
274
+
275
+ Examples:
276
+ ```python
277
+ from fastapi import FastAPI, Request
278
+ from veadk.a2a.ve_middlewares import build_a2a_auth_middleware
279
+ from veadk.auth.ve_credential_service import VeCredentialService
280
+ from veadk.integrations.ve_identity import IdentityClient
281
+
282
+ app = FastAPI()
283
+ credential_service = VeCredentialService()
284
+
285
+ # Optional: Create identity client for TIP token support
286
+ # If not provided, uses global client from VeIdentityConfig
287
+ identity_client = IdentityClient(region="cn-beijing")
288
+
289
+ # Add middleware with TIP token support
290
+ app.add_middleware(
291
+ build_a2a_auth_middleware(
292
+ app_name="my_app",
293
+ credential_service=credential_service,
294
+ auth_method="header",
295
+ identity_client=identity_client, # Optional, uses global if not provided
296
+ )
297
+ )
298
+ ```
299
+ """
300
+
301
+ class ConfiguredA2AAuthMiddleware(A2AAuthMiddleware):
302
+ def __init__(self, app):
303
+ super().__init__(
304
+ app=app,
305
+ app_name=app_name,
306
+ credential_service=credential_service,
307
+ auth_method=auth_method,
308
+ token_param=token_param,
309
+ credential_key=credential_key,
310
+ identity_client=identity_client,
311
+ )
312
+
313
+ return ConfiguredA2AAuthMiddleware
@@ -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 a2a.server.tasks import TaskStore
16
+ from a2a.types import Task
17
+ from typing_extensions import override
18
+
19
+
20
+ class VeTaskStore(TaskStore):
21
+ def __init__(self):
22
+ super().__init__()
23
+
24
+ @override
25
+ async def save(self, task: Task) -> None:
26
+ """Saves or updates a task in the store."""
27
+ return None
28
+
29
+ @override
30
+ async def get(self, task_id: str) -> Task | None:
31
+ """Retrieves a task from the store by ID."""
32
+ return None
33
+
34
+ @override
35
+ async def delete(self, task_id: str) -> None:
36
+ """Deletes a task from the store by ID."""
37
+ return None