feat(agent-runtime): 接入多服务商安全配置
This commit is contained in:
+109
-3
@@ -1,10 +1,21 @@
|
||||
"""当前用户的 Agent Run 查询页面。"""
|
||||
"""当前用户的 Agent Run 与模型服务商配置页面。"""
|
||||
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.core.paginator import Paginator
|
||||
from django.shortcuts import get_object_or_404, render
|
||||
from django.shortcuts import get_object_or_404, redirect, render
|
||||
|
||||
from .services import runs_for_user
|
||||
from common.exceptions import AgentConfigurationError, ProviderConnectionError
|
||||
|
||||
from .forms import ProviderConfigurationForm
|
||||
from .providers import CATEGORY_LABELS, PROVIDERS, get_provider
|
||||
from .services import (
|
||||
disconnect_provider,
|
||||
provider_configs_for_user,
|
||||
runs_for_user,
|
||||
save_verified_provider_config,
|
||||
verify_provider_api_key,
|
||||
)
|
||||
|
||||
|
||||
@login_required
|
||||
@@ -23,3 +34,98 @@ def run_detail(request, run_id):
|
||||
runs_for_user(request.user).prefetch_related("events", "tool_calls", "approvals"), pk=run_id
|
||||
)
|
||||
return render(request, "agent_runtime/run_detail.html", {"run": run})
|
||||
|
||||
|
||||
def _provider_page_context(request, form=None):
|
||||
"""构造纯展示视图模型,模板不承担查询、权限或协议判断。"""
|
||||
|
||||
configs = {item.provider_code: item for item in provider_configs_for_user(request.user)}
|
||||
category = request.GET.get("category", "all")
|
||||
query = request.GET.get("q", "").strip().lower()
|
||||
selected = get_provider(request.GET.get("provider", ""))
|
||||
cards = []
|
||||
for provider in PROVIDERS:
|
||||
config = configs.get(provider.code)
|
||||
if category == "connected" and config is None:
|
||||
continue
|
||||
if category not in {"all", "connected"} and provider.category != category:
|
||||
continue
|
||||
searchable = f"{provider.name} {provider.vendor} {provider.code}".lower()
|
||||
if query and query not in searchable:
|
||||
continue
|
||||
cards.append({"provider": provider, "config": config})
|
||||
selected_config = configs.get(selected.code) if selected else None
|
||||
return {
|
||||
"cards": cards,
|
||||
"provider_count": len(PROVIDERS),
|
||||
"connected_count": len(configs),
|
||||
"categories": CATEGORY_LABELS,
|
||||
"active_category": category if category in CATEGORY_LABELS else "all",
|
||||
"query": request.GET.get("q", "").strip(),
|
||||
"selected_provider": selected,
|
||||
"selected_config": selected_config,
|
||||
"provider_form": form
|
||||
or ProviderConfigurationForm(
|
||||
initial={
|
||||
"model_id": selected_config.default_model_id if selected_config else "",
|
||||
"use_as_default": selected_config.is_default if selected_config else False,
|
||||
}
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
@login_required
|
||||
def provider_list(request):
|
||||
"""展示当前用户的服务商目录和已连接状态。"""
|
||||
|
||||
return render(request, "agent_runtime/provider_list.html", _provider_page_context(request))
|
||||
|
||||
|
||||
@login_required
|
||||
def provider_configure(request, provider_code):
|
||||
"""验证并保存当前用户的 API Key;失败时不覆盖已有配置。"""
|
||||
|
||||
provider = get_provider(provider_code)
|
||||
if provider is None:
|
||||
return redirect("agent_runtime:provider-list")
|
||||
if request.method != "POST":
|
||||
return redirect(f"{redirect('agent_runtime:provider-list').url}?provider={provider.code}")
|
||||
form = ProviderConfigurationForm(request.POST)
|
||||
if not provider.key_only:
|
||||
messages.info(request, provider.note or "该服务商需要额外配置,当前版本尚未开放。")
|
||||
return redirect(f"{redirect('agent_runtime:provider-list').url}?provider={provider.code}")
|
||||
if form.is_valid():
|
||||
try:
|
||||
result = verify_provider_api_key(provider, form.cleaned_data["api_key"])
|
||||
save_verified_provider_config(
|
||||
request.user,
|
||||
provider,
|
||||
form.cleaned_data["api_key"],
|
||||
result,
|
||||
model_id=form.cleaned_data["model_id"],
|
||||
use_as_default=form.cleaned_data["use_as_default"],
|
||||
)
|
||||
except (ProviderConnectionError, AgentConfigurationError) as exc:
|
||||
form.add_error(None, str(exc))
|
||||
else:
|
||||
messages.success(request, f"{provider.name} 已验证并启用。")
|
||||
return redirect("agent_runtime:provider-list")
|
||||
# POST 出错时保持配置抽屉打开,且表单只回显非敏感错误,不回显已有密钥。
|
||||
query = request.GET.copy()
|
||||
query["provider"] = provider.code
|
||||
request.GET = query
|
||||
return render(
|
||||
request,
|
||||
"agent_runtime/provider_list.html",
|
||||
_provider_page_context(request, form),
|
||||
status=400,
|
||||
)
|
||||
|
||||
|
||||
@login_required
|
||||
def provider_disconnect(request, provider_code):
|
||||
"""仅接受 POST 断开当前用户自己的服务商配置。"""
|
||||
|
||||
if request.method == "POST" and disconnect_provider(request.user, provider_code):
|
||||
messages.success(request, "服务商配置已移除。")
|
||||
return redirect("agent_runtime:provider-list")
|
||||
|
||||
Reference in New Issue
Block a user