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.
- veadk/__init__.py +37 -0
- veadk/a2a/__init__.py +13 -0
- veadk/a2a/agent_card.py +45 -0
- veadk/a2a/remote_ve_agent.py +390 -0
- veadk/a2a/utils/__init__.py +13 -0
- veadk/a2a/utils/agent_to_a2a.py +170 -0
- veadk/a2a/ve_a2a_server.py +93 -0
- veadk/a2a/ve_agent_executor.py +78 -0
- veadk/a2a/ve_middlewares.py +313 -0
- veadk/a2a/ve_task_store.py +37 -0
- veadk/agent.py +402 -0
- veadk/agent_builder.py +93 -0
- veadk/agents/loop_agent.py +68 -0
- veadk/agents/parallel_agent.py +72 -0
- veadk/agents/sequential_agent.py +64 -0
- veadk/auth/__init__.py +13 -0
- veadk/auth/base_auth.py +22 -0
- veadk/auth/ve_credential_service.py +203 -0
- veadk/auth/veauth/__init__.py +13 -0
- veadk/auth/veauth/apmplus_veauth.py +58 -0
- veadk/auth/veauth/ark_veauth.py +75 -0
- veadk/auth/veauth/base_veauth.py +50 -0
- veadk/auth/veauth/cozeloop_veauth.py +13 -0
- veadk/auth/veauth/opensearch_veauth.py +75 -0
- veadk/auth/veauth/postgresql_veauth.py +75 -0
- veadk/auth/veauth/prompt_pilot_veauth.py +60 -0
- veadk/auth/veauth/speech_veauth.py +54 -0
- veadk/auth/veauth/utils.py +69 -0
- veadk/auth/veauth/vesearch_veauth.py +62 -0
- veadk/auth/veauth/viking_mem0_veauth.py +91 -0
- veadk/cli/__init__.py +13 -0
- veadk/cli/cli.py +58 -0
- veadk/cli/cli_clean.py +87 -0
- veadk/cli/cli_create.py +163 -0
- veadk/cli/cli_deploy.py +233 -0
- veadk/cli/cli_eval.py +215 -0
- veadk/cli/cli_init.py +214 -0
- veadk/cli/cli_kb.py +110 -0
- veadk/cli/cli_pipeline.py +285 -0
- veadk/cli/cli_prompt.py +86 -0
- veadk/cli/cli_update.py +106 -0
- veadk/cli/cli_uploadevalset.py +139 -0
- veadk/cli/cli_web.py +143 -0
- veadk/cloud/__init__.py +13 -0
- veadk/cloud/cloud_agent_engine.py +485 -0
- veadk/cloud/cloud_app.py +475 -0
- veadk/config.py +115 -0
- veadk/configs/__init__.py +13 -0
- veadk/configs/auth_configs.py +133 -0
- veadk/configs/database_configs.py +132 -0
- veadk/configs/model_configs.py +78 -0
- veadk/configs/tool_configs.py +54 -0
- veadk/configs/tracing_configs.py +110 -0
- veadk/consts.py +74 -0
- veadk/evaluation/__init__.py +17 -0
- veadk/evaluation/adk_evaluator/__init__.py +17 -0
- veadk/evaluation/adk_evaluator/adk_evaluator.py +302 -0
- veadk/evaluation/base_evaluator.py +642 -0
- veadk/evaluation/deepeval_evaluator/__init__.py +17 -0
- veadk/evaluation/deepeval_evaluator/deepeval_evaluator.py +339 -0
- veadk/evaluation/eval_set_file_loader.py +48 -0
- veadk/evaluation/eval_set_recorder.py +146 -0
- veadk/evaluation/types.py +65 -0
- veadk/evaluation/utils/prometheus.py +196 -0
- veadk/integrations/__init__.py +13 -0
- veadk/integrations/ve_apig/__init__.py +13 -0
- veadk/integrations/ve_apig/ve_apig.py +349 -0
- veadk/integrations/ve_apig/ve_apig_utils.py +332 -0
- veadk/integrations/ve_code_pipeline/__init__.py +13 -0
- veadk/integrations/ve_code_pipeline/ve_code_pipeline.py +431 -0
- veadk/integrations/ve_cozeloop/__init__.py +13 -0
- veadk/integrations/ve_cozeloop/ve_cozeloop.py +96 -0
- veadk/integrations/ve_cr/__init__.py +13 -0
- veadk/integrations/ve_cr/ve_cr.py +220 -0
- veadk/integrations/ve_faas/__init__.py +13 -0
- veadk/integrations/ve_faas/template/cookiecutter.json +15 -0
- veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/__init__.py +13 -0
- veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/clean.py +23 -0
- veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/config.yaml.example +6 -0
- veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/deploy.py +106 -0
- veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/__init__.py +13 -0
- veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/agent.py +25 -0
- veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/app.py +202 -0
- veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/requirements.txt +3 -0
- veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/run.sh +49 -0
- veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/{{ cookiecutter.app_name }}/__init__.py +14 -0
- veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/{{ cookiecutter.app_name }}/agent.py +27 -0
- veadk/integrations/ve_faas/ve_faas.py +754 -0
- veadk/integrations/ve_faas/ve_faas_utils.py +408 -0
- veadk/integrations/ve_faas/web_template/cookiecutter.json +20 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/__init__.py +13 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/clean.py +23 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/config.yaml.example +2 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/deploy.py +44 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/Dockerfile +23 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/app.py +123 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/init_db.py +46 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/models.py +36 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/requirements.txt +4 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/run.sh +21 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/static/css/style.css +368 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/static/js/admin.js +0 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/admin/dashboard.html +21 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/admin/edit_post.html +24 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/admin/login.html +21 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/admin/posts.html +53 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/base.html +45 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/index.html +29 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/post.html +14 -0
- veadk/integrations/ve_identity/__init__.py +110 -0
- veadk/integrations/ve_identity/auth_config.py +261 -0
- veadk/integrations/ve_identity/auth_mixins.py +650 -0
- veadk/integrations/ve_identity/auth_processor.py +385 -0
- veadk/integrations/ve_identity/function_tool.py +158 -0
- veadk/integrations/ve_identity/identity_client.py +864 -0
- veadk/integrations/ve_identity/mcp_tool.py +181 -0
- veadk/integrations/ve_identity/mcp_toolset.py +431 -0
- veadk/integrations/ve_identity/models.py +228 -0
- veadk/integrations/ve_identity/token_manager.py +188 -0
- veadk/integrations/ve_identity/utils.py +151 -0
- veadk/integrations/ve_prompt_pilot/__init__.py +13 -0
- veadk/integrations/ve_prompt_pilot/ve_prompt_pilot.py +85 -0
- veadk/integrations/ve_tls/__init__.py +13 -0
- veadk/integrations/ve_tls/utils.py +116 -0
- veadk/integrations/ve_tls/ve_tls.py +212 -0
- veadk/integrations/ve_tos/ve_tos.py +710 -0
- veadk/integrations/ve_viking_db_memory/__init__.py +13 -0
- veadk/integrations/ve_viking_db_memory/ve_viking_db_memory.py +308 -0
- veadk/knowledgebase/__init__.py +17 -0
- veadk/knowledgebase/backends/__init__.py +13 -0
- veadk/knowledgebase/backends/base_backend.py +72 -0
- veadk/knowledgebase/backends/in_memory_backend.py +91 -0
- veadk/knowledgebase/backends/opensearch_backend.py +162 -0
- veadk/knowledgebase/backends/redis_backend.py +172 -0
- veadk/knowledgebase/backends/utils.py +92 -0
- veadk/knowledgebase/backends/vikingdb_knowledge_backend.py +608 -0
- veadk/knowledgebase/entry.py +25 -0
- veadk/knowledgebase/knowledgebase.py +307 -0
- veadk/memory/__init__.py +35 -0
- veadk/memory/long_term_memory.py +365 -0
- veadk/memory/long_term_memory_backends/__init__.py +13 -0
- veadk/memory/long_term_memory_backends/base_backend.py +35 -0
- veadk/memory/long_term_memory_backends/in_memory_backend.py +67 -0
- veadk/memory/long_term_memory_backends/mem0_backend.py +155 -0
- veadk/memory/long_term_memory_backends/opensearch_backend.py +124 -0
- veadk/memory/long_term_memory_backends/redis_backend.py +140 -0
- veadk/memory/long_term_memory_backends/vikingdb_memory_backend.py +189 -0
- veadk/memory/short_term_memory.py +252 -0
- veadk/memory/short_term_memory_backends/__init__.py +13 -0
- veadk/memory/short_term_memory_backends/base_backend.py +31 -0
- veadk/memory/short_term_memory_backends/mysql_backend.py +49 -0
- veadk/memory/short_term_memory_backends/postgresql_backend.py +49 -0
- veadk/memory/short_term_memory_backends/sqlite_backend.py +55 -0
- veadk/memory/short_term_memory_processor.py +100 -0
- veadk/processors/__init__.py +26 -0
- veadk/processors/base_run_processor.py +120 -0
- veadk/prompts/__init__.py +13 -0
- veadk/prompts/agent_default_prompt.py +30 -0
- veadk/prompts/prompt_evaluator.py +20 -0
- veadk/prompts/prompt_memory_processor.py +55 -0
- veadk/prompts/prompt_optimization.py +150 -0
- veadk/runner.py +732 -0
- veadk/tools/__init__.py +13 -0
- veadk/tools/builtin_tools/__init__.py +13 -0
- veadk/tools/builtin_tools/agent_authorization.py +94 -0
- veadk/tools/builtin_tools/generate_image.py +23 -0
- veadk/tools/builtin_tools/image_edit.py +300 -0
- veadk/tools/builtin_tools/image_generate.py +446 -0
- veadk/tools/builtin_tools/lark.py +67 -0
- veadk/tools/builtin_tools/las.py +24 -0
- veadk/tools/builtin_tools/link_reader.py +66 -0
- veadk/tools/builtin_tools/llm_shield.py +381 -0
- veadk/tools/builtin_tools/load_knowledgebase.py +97 -0
- veadk/tools/builtin_tools/mcp_router.py +29 -0
- veadk/tools/builtin_tools/run_code.py +113 -0
- veadk/tools/builtin_tools/tts.py +253 -0
- veadk/tools/builtin_tools/vesearch.py +49 -0
- veadk/tools/builtin_tools/video_generate.py +363 -0
- veadk/tools/builtin_tools/web_scraper.py +76 -0
- veadk/tools/builtin_tools/web_search.py +83 -0
- veadk/tools/demo_tools.py +58 -0
- veadk/tools/load_knowledgebase_tool.py +149 -0
- veadk/tools/sandbox/__init__.py +13 -0
- veadk/tools/sandbox/browser_sandbox.py +37 -0
- veadk/tools/sandbox/code_sandbox.py +40 -0
- veadk/tools/sandbox/computer_sandbox.py +34 -0
- veadk/tracing/__init__.py +13 -0
- veadk/tracing/base_tracer.py +58 -0
- veadk/tracing/telemetry/__init__.py +13 -0
- veadk/tracing/telemetry/attributes/attributes.py +29 -0
- veadk/tracing/telemetry/attributes/extractors/common_attributes_extractors.py +180 -0
- veadk/tracing/telemetry/attributes/extractors/llm_attributes_extractors.py +858 -0
- veadk/tracing/telemetry/attributes/extractors/tool_attributes_extractors.py +152 -0
- veadk/tracing/telemetry/attributes/extractors/types.py +164 -0
- veadk/tracing/telemetry/exporters/__init__.py +13 -0
- veadk/tracing/telemetry/exporters/apmplus_exporter.py +558 -0
- veadk/tracing/telemetry/exporters/base_exporter.py +39 -0
- veadk/tracing/telemetry/exporters/cozeloop_exporter.py +129 -0
- veadk/tracing/telemetry/exporters/inmemory_exporter.py +248 -0
- veadk/tracing/telemetry/exporters/tls_exporter.py +139 -0
- veadk/tracing/telemetry/opentelemetry_tracer.py +320 -0
- veadk/tracing/telemetry/telemetry.py +411 -0
- veadk/types.py +47 -0
- veadk/utils/__init__.py +13 -0
- veadk/utils/audio_manager.py +95 -0
- veadk/utils/auth.py +294 -0
- veadk/utils/logger.py +59 -0
- veadk/utils/mcp_utils.py +44 -0
- veadk/utils/misc.py +184 -0
- veadk/utils/patches.py +101 -0
- veadk/utils/volcengine_sign.py +205 -0
- veadk/version.py +15 -0
- veadk_python-0.2.27.dist-info/METADATA +373 -0
- veadk_python-0.2.27.dist-info/RECORD +218 -0
- veadk_python-0.2.27.dist-info/WHEEL +5 -0
- veadk_python-0.2.27.dist-info/entry_points.txt +2 -0
- veadk_python-0.2.27.dist-info/licenses/LICENSE +201 -0
- 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
|