Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
- Add welcomeMessage/quickCommands fields to Clone interface - Persist template welcome/quick data via updateClone after creation - FirstConversationPrompt: prefer template-provided welcome message over dynamically generated one - FirstConversationPrompt: render template quick_commands as chips instead of hardcoded QUICK_ACTIONS when available - Tighten assign/unassign template endpoint permissions from model:read to relay:use (self-service operation for all authenticated users)
191 lines
6.7 KiB
Rust
191 lines
6.7 KiB
Rust
//! Agent 配置模板 HTTP 处理器
|
|
|
|
use axum::{
|
|
extract::{Extension, Path, Query, State},
|
|
Json,
|
|
};
|
|
use crate::state::AppState;
|
|
use crate::error::SaasResult;
|
|
use crate::auth::types::AuthContext;
|
|
use crate::auth::handlers::{log_operation, check_permission};
|
|
use super::types::*;
|
|
use super::service;
|
|
|
|
/// GET /api/v1/agent-templates — 列出 Agent 模板
|
|
pub async fn list_templates(
|
|
State(state): State<AppState>,
|
|
Extension(ctx): Extension<AuthContext>,
|
|
Query(query): Query<AgentTemplateListQuery>,
|
|
) -> SaasResult<Json<crate::common::PaginatedResponse<AgentTemplateInfo>>> {
|
|
check_permission(&ctx, "model:read")?;
|
|
Ok(Json(service::list_templates(&state.db, &query).await?))
|
|
}
|
|
|
|
/// POST /api/v1/agent-templates — 创建 Agent 模板
|
|
pub async fn create_template(
|
|
State(state): State<AppState>,
|
|
Extension(ctx): Extension<AuthContext>,
|
|
Json(req): Json<CreateAgentTemplateRequest>,
|
|
) -> SaasResult<Json<AgentTemplateInfo>> {
|
|
check_permission(&ctx, "model:manage")?;
|
|
|
|
let category = req.category.as_deref().unwrap_or("general");
|
|
let source = req.source.as_deref().unwrap_or("custom");
|
|
let visibility = req.visibility.as_deref().unwrap_or("public");
|
|
let tools = req.tools.as_deref().unwrap_or(&[]);
|
|
let capabilities = req.capabilities.as_deref().unwrap_or(&[]);
|
|
let scenarios = req.scenarios.as_deref().unwrap_or(&[]);
|
|
let quick_commands = req.quick_commands.as_deref().unwrap_or(&[]);
|
|
|
|
let result = service::create_template(
|
|
&state.db, &req.name, req.description.as_deref(),
|
|
category, source, req.model.as_deref(),
|
|
req.system_prompt.as_deref(),
|
|
tools, capabilities,
|
|
req.temperature, req.max_tokens, visibility,
|
|
req.soul_content.as_deref(),
|
|
Some(scenarios),
|
|
req.welcome_message.as_deref(),
|
|
Some(quick_commands),
|
|
req.personality.as_deref(),
|
|
req.communication_style.as_deref(),
|
|
req.emoji.as_deref(),
|
|
req.source_id.as_deref(),
|
|
).await?;
|
|
|
|
log_operation(&state.db, &ctx.account_id, "agent_template.create", "agent_template", &result.id,
|
|
Some(serde_json::json!({"name": req.name})), ctx.client_ip.as_deref()).await?;
|
|
|
|
Ok(Json(result))
|
|
}
|
|
|
|
/// GET /api/v1/agent-templates/:id — 获取单个 Agent 模板
|
|
pub async fn get_template(
|
|
State(state): State<AppState>,
|
|
Extension(ctx): Extension<AuthContext>,
|
|
Path(id): Path<String>,
|
|
) -> SaasResult<Json<AgentTemplateInfo>> {
|
|
check_permission(&ctx, "model:read")?;
|
|
Ok(Json(service::get_template(&state.db, &id).await?))
|
|
}
|
|
|
|
/// GET /api/v1/agent-templates/:id/full — 获取完整 Agent 模板(含扩展字段)
|
|
pub async fn get_full_template(
|
|
State(state): State<AppState>,
|
|
Extension(ctx): Extension<AuthContext>,
|
|
Path(id): Path<String>,
|
|
) -> SaasResult<Json<AgentTemplateInfo>> {
|
|
check_permission(&ctx, "model:read")?;
|
|
// Reuses the same get_template service which already returns all fields
|
|
Ok(Json(service::get_template(&state.db, &id).await?))
|
|
}
|
|
|
|
/// GET /api/v1/agent-templates/available — 列出公开可用模板(轻量级)
|
|
pub async fn list_available(
|
|
State(state): State<AppState>,
|
|
Extension(ctx): Extension<AuthContext>,
|
|
) -> SaasResult<Json<Vec<AvailableAgentTemplateInfo>>> {
|
|
check_permission(&ctx, "model:read")?;
|
|
Ok(Json(service::list_available(&state.db).await?))
|
|
}
|
|
|
|
/// POST /api/v1/agent-templates/:id — 更新 Agent 模板
|
|
pub async fn update_template(
|
|
State(state): State<AppState>,
|
|
Extension(ctx): Extension<AuthContext>,
|
|
Path(id): Path<String>,
|
|
Json(req): Json<UpdateAgentTemplateRequest>,
|
|
) -> SaasResult<Json<AgentTemplateInfo>> {
|
|
check_permission(&ctx, "model:manage")?;
|
|
|
|
let result = service::update_template(
|
|
&state.db, &id,
|
|
req.description.as_deref(),
|
|
req.model.as_deref(),
|
|
req.system_prompt.as_deref(),
|
|
req.tools.as_deref(),
|
|
req.capabilities.as_deref(),
|
|
req.temperature,
|
|
req.max_tokens,
|
|
req.visibility.as_deref(),
|
|
req.status.as_deref(),
|
|
req.soul_content.as_deref(),
|
|
req.scenarios.as_deref(),
|
|
req.welcome_message.as_deref(),
|
|
req.quick_commands.as_deref(),
|
|
req.personality.as_deref(),
|
|
req.communication_style.as_deref(),
|
|
req.emoji.as_deref(),
|
|
).await?;
|
|
|
|
log_operation(&state.db, &ctx.account_id, "agent_template.update", "agent_template", &id,
|
|
None, ctx.client_ip.as_deref()).await?;
|
|
|
|
Ok(Json(result))
|
|
}
|
|
|
|
/// DELETE /api/v1/agent-templates/:id — 归档 Agent 模板
|
|
pub async fn archive_template(
|
|
State(state): State<AppState>,
|
|
Extension(ctx): Extension<AuthContext>,
|
|
Path(id): Path<String>,
|
|
) -> SaasResult<Json<AgentTemplateInfo>> {
|
|
check_permission(&ctx, "model:manage")?;
|
|
|
|
let result = service::archive_template(&state.db, &id).await?;
|
|
|
|
log_operation(&state.db, &ctx.account_id, "agent_template.archive", "agent_template", &id,
|
|
None, ctx.client_ip.as_deref()).await?;
|
|
|
|
Ok(Json(result))
|
|
}
|
|
|
|
// --- Template Assignment ---
|
|
|
|
/// POST /api/v1/accounts/me/assign-template — 分配行业模板到当前账户
|
|
pub async fn assign_template(
|
|
State(state): State<AppState>,
|
|
Extension(ctx): Extension<AuthContext>,
|
|
Json(req): Json<AssignTemplateRequest>,
|
|
) -> SaasResult<Json<AgentTemplateInfo>> {
|
|
check_permission(&ctx, "relay:use")?;
|
|
|
|
let result = service::assign_template_to_account(
|
|
&state.db, &ctx.account_id, &req.template_id,
|
|
).await?;
|
|
|
|
log_operation(&state.db, &ctx.account_id, "account.assign_template", "agent_template", &req.template_id,
|
|
None, ctx.client_ip.as_deref()).await?;
|
|
|
|
Ok(Json(result))
|
|
}
|
|
|
|
/// GET /api/v1/accounts/me/assigned-template — 获取已分配的行业模板
|
|
pub async fn get_assigned_template(
|
|
State(state): State<AppState>,
|
|
Extension(ctx): Extension<AuthContext>,
|
|
) -> SaasResult<Json<Option<AgentTemplateInfo>>> {
|
|
check_permission(&ctx, "model:read")?;
|
|
Ok(Json(service::get_assigned_template(&state.db, &ctx.account_id).await?))
|
|
}
|
|
|
|
/// DELETE /api/v1/accounts/me/assigned-template — 取消行业模板分配
|
|
pub async fn unassign_template(
|
|
State(state): State<AppState>,
|
|
Extension(ctx): Extension<AuthContext>,
|
|
) -> SaasResult<Json<serde_json::Value>> {
|
|
check_permission(&ctx, "relay:use")?;
|
|
service::unassign_template(&state.db, &ctx.account_id).await?;
|
|
Ok(Json(serde_json::json!({"ok": true})))
|
|
}
|
|
|
|
/// POST /api/v1/agent-templates/:id/create-agent — 从模板创建 Agent 配置
|
|
pub async fn create_agent_from_template(
|
|
State(state): State<AppState>,
|
|
Extension(ctx): Extension<AuthContext>,
|
|
Path(id): Path<String>,
|
|
) -> SaasResult<Json<AgentConfigFromTemplate>> {
|
|
check_permission(&ctx, "model:read")?;
|
|
Ok(Json(service::create_agent_from_template(&state.db, &id).await?))
|
|
}
|