refactor: 对象命名标准化落地(RoleKind→ObjectKind、capability/assistant 收口)
后端 - model.SkillDefinition.RoleKind 改名 ObjectKind(列 role_kind → object_kind); 新增 migrateSkillObjectKindColumn:先拷数据再显式 drop 旧列。 GORM AutoMigrate 只加不删,字段改名不手写迁移就会新旧两列并存。 - Specialist 结构化列更名走同一套 migrateColumnData: role_card_json → interaction_card_json、source_records_json → inputs_records_json - api/capability_definition.go(413 行)拆为 skill_action_definition.go, 不再让 capability 充当一级对象名;该文件同时承载技能与动作定义处理器 - 新增 model/app_definition.go + api/app_definition.go:应用目录定义正式建模 - SkillDefinition 移除已废弃的 LegacyObjectEntryRoute 字段,对应迁移分支一并删除 - skill_keys.go 注释更新:权威来源为前端 staticSkillCatalog 前端 - api/assistant.js → chat.js、api/capability.js → skill.js,新增 api/appDefinition.js - 新增 store/specialistCatalog.js、skillCatalog.js、appCatalog.js, 取代 config/productizedApps.js(已删) - config/workbench.js 静态目录去失真:businessApps → staticSpecialistCatalog (该变量装的其实是专员目录,与应用 app 语义直接冲突)、 availableSkills → staticSkillCatalog - 修复入口 query 协议断裂:写端 appCatalog 用 app_specialist/app_skill/app_prompt, 读端 SmartAssistantPage 读同名参数并挂响应式监听。 此前写读两侧命名不一致且无人读旧名,导致从应用目录打开应用时 预置专员/技能/提示词被静默丢弃、无任何报错 - 页面与组件局部变量去失真:拿到专员对象不再命名为 app 验证:CGO_ENABLED=0 go build ./... 通过;go test ./... 全包通过;npm run build 通过。 旧变量名 businessApps / availableSkills / productizedApps / api/capability / api/assistant 全仓 grep 无残留。 Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,233 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"eai_agentplatform/backend/internal/model"
|
||||
"eai_agentplatform/backend/internal/store"
|
||||
"eai_agentplatform/backend/internal/web"
|
||||
)
|
||||
|
||||
type appDefinitionReq struct {
|
||||
Key string `json:"key"`
|
||||
Label string `json:"label"`
|
||||
Badge string `json:"badge"`
|
||||
Kind string `json:"kind"`
|
||||
MarketTag string `json:"market_tag"`
|
||||
WorkerType string `json:"worker_type"`
|
||||
Tier string `json:"tier"`
|
||||
Source string `json:"source"`
|
||||
Color string `json:"color"`
|
||||
IconText string `json:"icon_text"`
|
||||
CoverTone string `json:"cover_tone"`
|
||||
Summary string `json:"summary"`
|
||||
Description string `json:"description"`
|
||||
OpenRoute string `json:"open_route"`
|
||||
SpecialistKey string `json:"specialist_key"`
|
||||
SkillKey string `json:"skill_key"`
|
||||
DefaultPrompt string `json:"default_prompt"`
|
||||
PromptsJSON string `json:"prompts_json"`
|
||||
TagsJSON string `json:"tags_json"`
|
||||
InstallState string `json:"install_state"`
|
||||
ExposedToUser bool `json:"exposed_to_user"`
|
||||
State string `json:"state"`
|
||||
SortOrder int `json:"sort_order"`
|
||||
}
|
||||
|
||||
func normalizeAppDefinitionReq(req *appDefinitionReq) {
|
||||
req.Key = strings.TrimSpace(req.Key)
|
||||
req.Label = strings.TrimSpace(req.Label)
|
||||
req.Badge = strings.TrimSpace(req.Badge)
|
||||
req.Kind = strings.TrimSpace(req.Kind)
|
||||
req.MarketTag = strings.TrimSpace(req.MarketTag)
|
||||
req.WorkerType = strings.TrimSpace(req.WorkerType)
|
||||
req.Tier = strings.TrimSpace(req.Tier)
|
||||
req.Source = strings.TrimSpace(req.Source)
|
||||
req.Color = strings.TrimSpace(req.Color)
|
||||
req.IconText = strings.TrimSpace(req.IconText)
|
||||
req.CoverTone = strings.TrimSpace(req.CoverTone)
|
||||
req.Summary = strings.TrimSpace(req.Summary)
|
||||
req.Description = strings.TrimSpace(req.Description)
|
||||
req.OpenRoute = strings.TrimSpace(req.OpenRoute)
|
||||
req.SpecialistKey = strings.TrimSpace(req.SpecialistKey)
|
||||
req.SkillKey = strings.TrimSpace(req.SkillKey)
|
||||
req.DefaultPrompt = strings.TrimSpace(req.DefaultPrompt)
|
||||
req.PromptsJSON = strings.TrimSpace(req.PromptsJSON)
|
||||
req.TagsJSON = strings.TrimSpace(req.TagsJSON)
|
||||
req.InstallState = strings.TrimSpace(req.InstallState)
|
||||
req.State = strings.TrimSpace(req.State)
|
||||
}
|
||||
|
||||
func validateAppDefinitionReq(req *appDefinitionReq) *web.AppError {
|
||||
normalizeAppDefinitionReq(req)
|
||||
if req.Key == "" || req.Label == "" {
|
||||
return web.NewBadRequest("key、label 为必填")
|
||||
}
|
||||
if req.WorkerType == "" {
|
||||
req.WorkerType = "worker"
|
||||
}
|
||||
if req.Tier == "" {
|
||||
req.Tier = "business"
|
||||
}
|
||||
if req.Source == "" {
|
||||
req.Source = "eai"
|
||||
}
|
||||
if req.InstallState == "" {
|
||||
req.InstallState = "installed"
|
||||
}
|
||||
if req.State == "" {
|
||||
req.State = "active"
|
||||
}
|
||||
if req.State != "active" && req.State != "inactive" {
|
||||
return web.NewBadRequest("state 只能是 active 或 inactive")
|
||||
}
|
||||
if !store.ValidateJSONStringArray(req.PromptsJSON) {
|
||||
return web.NewBadRequest("prompts_json 必须是字符串数组")
|
||||
}
|
||||
if !store.ValidateJSONStringArray(req.TagsJSON) {
|
||||
return web.NewBadRequest("tags_json 必须是字符串数组")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ListAppDefinitions(c *gin.Context) {
|
||||
q := store.DB.Model(&model.AppDefinition{})
|
||||
if c.Query("state") == "" {
|
||||
q = q.Where("state = ?", "active")
|
||||
} else {
|
||||
q = q.Where("state = ?", c.Query("state"))
|
||||
}
|
||||
if c.Query("exposed_to_user") != "" {
|
||||
q = q.Where("exposed_to_user = ?", c.Query("exposed_to_user") == "true")
|
||||
}
|
||||
var items []model.AppDefinition
|
||||
if err := q.Order("sort_order ASC, id ASC").Find(&items).Error; err != nil {
|
||||
web.Fail(c, web.NewBadRequest("查询应用定义失败"))
|
||||
return
|
||||
}
|
||||
web.OK(c, items)
|
||||
}
|
||||
|
||||
func GetAppDefinitionByKey(c *gin.Context) {
|
||||
key := strings.TrimSpace(c.Param("key"))
|
||||
if key == "" {
|
||||
web.Fail(c, web.NewBadRequest("应用 key 不能为空"))
|
||||
return
|
||||
}
|
||||
var item model.AppDefinition
|
||||
if err := store.DB.Where("key = ?", key).First(&item).Error; err != nil {
|
||||
web.Fail(c, web.NewNotFoundError("应用定义不存在"))
|
||||
return
|
||||
}
|
||||
web.OK(c, item)
|
||||
}
|
||||
|
||||
func CreateAppDefinition(c *gin.Context) {
|
||||
var req appDefinitionReq
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
web.Fail(c, web.NewBadRequest("请求参数错误"))
|
||||
return
|
||||
}
|
||||
if appErr := validateAppDefinitionReq(&req); appErr != nil {
|
||||
web.Fail(c, appErr)
|
||||
return
|
||||
}
|
||||
item := model.AppDefinition{
|
||||
Key: req.Key,
|
||||
Label: req.Label,
|
||||
Badge: req.Badge,
|
||||
Kind: req.Kind,
|
||||
MarketTag: req.MarketTag,
|
||||
WorkerType: req.WorkerType,
|
||||
Tier: req.Tier,
|
||||
Source: req.Source,
|
||||
Color: req.Color,
|
||||
IconText: req.IconText,
|
||||
CoverTone: req.CoverTone,
|
||||
Summary: req.Summary,
|
||||
Description: req.Description,
|
||||
OpenRoute: req.OpenRoute,
|
||||
SpecialistKey: req.SpecialistKey,
|
||||
SkillKey: req.SkillKey,
|
||||
DefaultPrompt: req.DefaultPrompt,
|
||||
PromptsJSON: req.PromptsJSON,
|
||||
TagsJSON: req.TagsJSON,
|
||||
InstallState: req.InstallState,
|
||||
ExposedToUser: req.ExposedToUser,
|
||||
State: req.State,
|
||||
SortOrder: req.SortOrder,
|
||||
}
|
||||
if err := store.DB.Create(&item).Error; err != nil {
|
||||
web.Fail(c, web.NewBadRequest("创建应用定义失败"))
|
||||
return
|
||||
}
|
||||
web.OK(c, item)
|
||||
}
|
||||
|
||||
func UpdateAppDefinition(c *gin.Context) {
|
||||
id, ok := parseID(c, "id")
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
var item model.AppDefinition
|
||||
if err := store.DB.First(&item, id).Error; err != nil {
|
||||
web.Fail(c, web.NewNotFoundError("应用定义不存在"))
|
||||
return
|
||||
}
|
||||
var req appDefinitionReq
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
web.Fail(c, web.NewBadRequest("请求参数错误"))
|
||||
return
|
||||
}
|
||||
if appErr := validateAppDefinitionReq(&req); appErr != nil {
|
||||
web.Fail(c, appErr)
|
||||
return
|
||||
}
|
||||
item.Key = req.Key
|
||||
item.Label = req.Label
|
||||
item.Badge = req.Badge
|
||||
item.Kind = req.Kind
|
||||
item.MarketTag = req.MarketTag
|
||||
item.WorkerType = req.WorkerType
|
||||
item.Tier = req.Tier
|
||||
item.Source = req.Source
|
||||
item.Color = req.Color
|
||||
item.IconText = req.IconText
|
||||
item.CoverTone = req.CoverTone
|
||||
item.Summary = req.Summary
|
||||
item.Description = req.Description
|
||||
item.OpenRoute = req.OpenRoute
|
||||
item.SpecialistKey = req.SpecialistKey
|
||||
item.SkillKey = req.SkillKey
|
||||
item.DefaultPrompt = req.DefaultPrompt
|
||||
item.PromptsJSON = req.PromptsJSON
|
||||
item.TagsJSON = req.TagsJSON
|
||||
item.InstallState = req.InstallState
|
||||
item.ExposedToUser = req.ExposedToUser
|
||||
item.State = req.State
|
||||
item.SortOrder = req.SortOrder
|
||||
if err := store.DB.Save(&item).Error; err != nil {
|
||||
web.Fail(c, web.NewBadRequest("更新应用定义失败"))
|
||||
return
|
||||
}
|
||||
web.OK(c, item)
|
||||
}
|
||||
|
||||
func DeleteAppDefinition(c *gin.Context) {
|
||||
id, ok := parseID(c, "id")
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
var item model.AppDefinition
|
||||
if err := store.DB.First(&item, id).Error; err != nil {
|
||||
web.Fail(c, web.NewNotFoundError("应用定义不存在"))
|
||||
return
|
||||
}
|
||||
if err := store.DB.Delete(&item).Error; err != nil {
|
||||
web.Fail(c, web.NewBadRequest("删除应用定义失败"))
|
||||
return
|
||||
}
|
||||
web.OK(c, gin.H{"id": id, "deleted": true})
|
||||
}
|
||||
@@ -1,413 +0,0 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"eai_agentplatform/backend/internal/model"
|
||||
"eai_agentplatform/backend/internal/store"
|
||||
"eai_agentplatform/backend/internal/web"
|
||||
)
|
||||
|
||||
type skillDefinitionReq struct {
|
||||
Key string `json:"key"`
|
||||
Label string `json:"label"`
|
||||
Description string `json:"description"`
|
||||
RoleKind string `json:"role_kind"`
|
||||
Source string `json:"source"`
|
||||
ObjectEntryRoute string `json:"object_entry_route"`
|
||||
LegacyObjectEntryRoute string `json:"legacy_object_entry_route"`
|
||||
ExposedToUser bool `json:"exposed_to_user"`
|
||||
StarterPromptsJSON string `json:"starter_prompts_json"`
|
||||
PromptTemplate string `json:"prompt_template"`
|
||||
InputSchemaJSON string `json:"input_schema_json"`
|
||||
OutputSchemaJSON string `json:"output_schema_json"`
|
||||
ArtifactSchemaJSON string `json:"artifact_schema_json"`
|
||||
ActionRefsJSON string `json:"action_refs_json"`
|
||||
PolicyRefsJSON string `json:"policy_refs_json"`
|
||||
OntologyBindingJSON string `json:"ontology_binding_json"`
|
||||
State string `json:"state"`
|
||||
SortOrder int `json:"sort_order"`
|
||||
}
|
||||
|
||||
type actionDefinitionReq struct {
|
||||
Key string `json:"key"`
|
||||
Label string `json:"label"`
|
||||
Description string `json:"description"`
|
||||
ActionType string `json:"action_type"`
|
||||
ConnectorRef string `json:"connector_ref"`
|
||||
InputSchemaJSON string `json:"input_schema_json"`
|
||||
OutputSchemaJSON string `json:"output_schema_json"`
|
||||
RiskLevel string `json:"risk_level"`
|
||||
ApprovalMode string `json:"approval_mode"`
|
||||
AuditLevel string `json:"audit_level"`
|
||||
ExposedToUser bool `json:"exposed_to_user"`
|
||||
OntologyBindingJSON string `json:"ontology_binding_json"`
|
||||
State string `json:"state"`
|
||||
SortOrder int `json:"sort_order"`
|
||||
}
|
||||
|
||||
func normalizeSkillDefinitionReq(req *skillDefinitionReq) {
|
||||
req.Key = strings.TrimSpace(req.Key)
|
||||
req.Label = strings.TrimSpace(req.Label)
|
||||
req.Description = strings.TrimSpace(req.Description)
|
||||
req.RoleKind = strings.TrimSpace(req.RoleKind)
|
||||
req.Source = strings.TrimSpace(req.Source)
|
||||
req.ObjectEntryRoute = strings.TrimSpace(req.ObjectEntryRoute)
|
||||
req.LegacyObjectEntryRoute = strings.TrimSpace(req.LegacyObjectEntryRoute)
|
||||
req.StarterPromptsJSON = strings.TrimSpace(req.StarterPromptsJSON)
|
||||
req.PromptTemplate = strings.TrimSpace(req.PromptTemplate)
|
||||
req.InputSchemaJSON = strings.TrimSpace(req.InputSchemaJSON)
|
||||
req.OutputSchemaJSON = strings.TrimSpace(req.OutputSchemaJSON)
|
||||
req.ArtifactSchemaJSON = strings.TrimSpace(req.ArtifactSchemaJSON)
|
||||
req.ActionRefsJSON = strings.TrimSpace(req.ActionRefsJSON)
|
||||
req.PolicyRefsJSON = strings.TrimSpace(req.PolicyRefsJSON)
|
||||
req.OntologyBindingJSON = strings.TrimSpace(req.OntologyBindingJSON)
|
||||
req.State = strings.TrimSpace(req.State)
|
||||
}
|
||||
|
||||
func validateSkillDefinitionReq(req *skillDefinitionReq) *web.AppError {
|
||||
normalizeSkillDefinitionReq(req)
|
||||
if req.Key == "" || req.Label == "" {
|
||||
return web.NewBadRequest("key、label 为必填")
|
||||
}
|
||||
if req.RoleKind == "" {
|
||||
req.RoleKind = "skill"
|
||||
}
|
||||
switch req.RoleKind {
|
||||
case "assistant", "specialist", "skill":
|
||||
default:
|
||||
return web.NewBadRequest("role_kind 只能是 assistant、specialist 或 skill")
|
||||
}
|
||||
if req.Source == "" {
|
||||
req.Source = "eai"
|
||||
}
|
||||
if req.State == "" {
|
||||
req.State = "active"
|
||||
}
|
||||
if req.State != "active" && req.State != "inactive" {
|
||||
return web.NewBadRequest("state 只能是 active 或 inactive")
|
||||
}
|
||||
if !store.ValidateJSONStringArray(req.StarterPromptsJSON) {
|
||||
return web.NewBadRequest("starter_prompts_json 必须是字符串数组")
|
||||
}
|
||||
if !store.ValidateJSONObjectJSON(req.InputSchemaJSON) {
|
||||
return web.NewBadRequest("input_schema_json 必须是 JSON 对象")
|
||||
}
|
||||
if !store.ValidateJSONObjectJSON(req.OutputSchemaJSON) {
|
||||
return web.NewBadRequest("output_schema_json 必须是 JSON 对象")
|
||||
}
|
||||
if !store.ValidateJSONObjectJSON(req.ArtifactSchemaJSON) {
|
||||
return web.NewBadRequest("artifact_schema_json 必须是 JSON 对象")
|
||||
}
|
||||
if !store.ValidateJSONStringArray(req.ActionRefsJSON) {
|
||||
return web.NewBadRequest("action_refs_json 必须是字符串数组")
|
||||
}
|
||||
if !store.ValidateJSONStringArray(req.PolicyRefsJSON) {
|
||||
return web.NewBadRequest("policy_refs_json 必须是字符串数组")
|
||||
}
|
||||
if !store.ValidateJSONObjectJSON(req.OntologyBindingJSON) {
|
||||
return web.NewBadRequest("ontology_binding_json 必须是 JSON 对象")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func normalizeActionDefinitionReq(req *actionDefinitionReq) {
|
||||
req.Key = strings.TrimSpace(req.Key)
|
||||
req.Label = strings.TrimSpace(req.Label)
|
||||
req.Description = strings.TrimSpace(req.Description)
|
||||
req.ActionType = strings.TrimSpace(req.ActionType)
|
||||
req.ConnectorRef = strings.TrimSpace(req.ConnectorRef)
|
||||
req.InputSchemaJSON = strings.TrimSpace(req.InputSchemaJSON)
|
||||
req.OutputSchemaJSON = strings.TrimSpace(req.OutputSchemaJSON)
|
||||
req.RiskLevel = strings.TrimSpace(req.RiskLevel)
|
||||
req.ApprovalMode = strings.TrimSpace(req.ApprovalMode)
|
||||
req.AuditLevel = strings.TrimSpace(req.AuditLevel)
|
||||
req.OntologyBindingJSON = strings.TrimSpace(req.OntologyBindingJSON)
|
||||
req.State = strings.TrimSpace(req.State)
|
||||
}
|
||||
|
||||
func validateActionDefinitionReq(req *actionDefinitionReq) *web.AppError {
|
||||
normalizeActionDefinitionReq(req)
|
||||
if req.Key == "" || req.Label == "" {
|
||||
return web.NewBadRequest("key、label 为必填")
|
||||
}
|
||||
if req.ActionType == "" {
|
||||
req.ActionType = "execution"
|
||||
}
|
||||
if req.RiskLevel == "" {
|
||||
req.RiskLevel = "low"
|
||||
}
|
||||
if req.ApprovalMode == "" {
|
||||
req.ApprovalMode = "not_required"
|
||||
}
|
||||
if req.AuditLevel == "" {
|
||||
req.AuditLevel = "standard"
|
||||
}
|
||||
if req.State == "" {
|
||||
req.State = "active"
|
||||
}
|
||||
if req.State != "active" && req.State != "inactive" {
|
||||
return web.NewBadRequest("state 只能是 active 或 inactive")
|
||||
}
|
||||
if !store.ValidateJSONObjectJSON(req.InputSchemaJSON) {
|
||||
return web.NewBadRequest("input_schema_json 必须是 JSON 对象")
|
||||
}
|
||||
if !store.ValidateJSONObjectJSON(req.OutputSchemaJSON) {
|
||||
return web.NewBadRequest("output_schema_json 必须是 JSON 对象")
|
||||
}
|
||||
if !store.ValidateJSONObjectJSON(req.OntologyBindingJSON) {
|
||||
return web.NewBadRequest("ontology_binding_json 必须是 JSON 对象")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ListSkillDefinitions(c *gin.Context) {
|
||||
q := store.DB.Model(&model.SkillDefinition{})
|
||||
if c.Query("state") == "" {
|
||||
q = q.Where("state = ?", "active")
|
||||
} else {
|
||||
q = q.Where("state = ?", c.Query("state"))
|
||||
}
|
||||
if c.Query("exposed_to_user") != "" {
|
||||
q = q.Where("exposed_to_user = ?", c.Query("exposed_to_user") == "true")
|
||||
}
|
||||
var items []model.SkillDefinition
|
||||
if err := q.Order("sort_order ASC, id ASC").Find(&items).Error; err != nil {
|
||||
web.Fail(c, web.NewBadRequest("查询技能定义失败"))
|
||||
return
|
||||
}
|
||||
web.OK(c, items)
|
||||
}
|
||||
|
||||
func GetSkillDefinitionByKey(c *gin.Context) {
|
||||
key := strings.TrimSpace(c.Param("key"))
|
||||
if key == "" {
|
||||
web.Fail(c, web.NewBadRequest("技能 key 不能为空"))
|
||||
return
|
||||
}
|
||||
var item model.SkillDefinition
|
||||
if err := store.DB.Where("key = ?", key).First(&item).Error; err != nil {
|
||||
web.Fail(c, web.NewNotFoundError("技能定义不存在"))
|
||||
return
|
||||
}
|
||||
web.OK(c, item)
|
||||
}
|
||||
|
||||
func CreateSkillDefinition(c *gin.Context) {
|
||||
var req skillDefinitionReq
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
web.Fail(c, web.NewBadRequest("请求参数错误"))
|
||||
return
|
||||
}
|
||||
if appErr := validateSkillDefinitionReq(&req); appErr != nil {
|
||||
web.Fail(c, appErr)
|
||||
return
|
||||
}
|
||||
item := model.SkillDefinition{
|
||||
Key: req.Key,
|
||||
Label: req.Label,
|
||||
Description: req.Description,
|
||||
RoleKind: req.RoleKind,
|
||||
Source: req.Source,
|
||||
ObjectEntryRoute: req.ObjectEntryRoute,
|
||||
LegacyObjectEntryRoute: req.LegacyObjectEntryRoute,
|
||||
ExposedToUser: req.ExposedToUser,
|
||||
StarterPromptsJSON: req.StarterPromptsJSON,
|
||||
PromptTemplate: req.PromptTemplate,
|
||||
InputSchemaJSON: req.InputSchemaJSON,
|
||||
OutputSchemaJSON: req.OutputSchemaJSON,
|
||||
ArtifactSchemaJSON: req.ArtifactSchemaJSON,
|
||||
ActionRefsJSON: req.ActionRefsJSON,
|
||||
PolicyRefsJSON: req.PolicyRefsJSON,
|
||||
OntologyBindingJSON: req.OntologyBindingJSON,
|
||||
State: req.State,
|
||||
SortOrder: req.SortOrder,
|
||||
}
|
||||
if err := store.DB.Create(&item).Error; err != nil {
|
||||
web.Fail(c, web.NewBadRequest("创建技能定义失败"))
|
||||
return
|
||||
}
|
||||
web.OK(c, item)
|
||||
}
|
||||
|
||||
func UpdateSkillDefinition(c *gin.Context) {
|
||||
id, ok := parseID(c, "id")
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
var item model.SkillDefinition
|
||||
if err := store.DB.First(&item, id).Error; err != nil {
|
||||
web.Fail(c, web.NewNotFoundError("技能定义不存在"))
|
||||
return
|
||||
}
|
||||
var req skillDefinitionReq
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
web.Fail(c, web.NewBadRequest("请求参数错误"))
|
||||
return
|
||||
}
|
||||
if appErr := validateSkillDefinitionReq(&req); appErr != nil {
|
||||
web.Fail(c, appErr)
|
||||
return
|
||||
}
|
||||
item.Key = req.Key
|
||||
item.Label = req.Label
|
||||
item.Description = req.Description
|
||||
item.RoleKind = req.RoleKind
|
||||
item.Source = req.Source
|
||||
item.ObjectEntryRoute = req.ObjectEntryRoute
|
||||
item.LegacyObjectEntryRoute = req.LegacyObjectEntryRoute
|
||||
item.ExposedToUser = req.ExposedToUser
|
||||
item.StarterPromptsJSON = req.StarterPromptsJSON
|
||||
item.PromptTemplate = req.PromptTemplate
|
||||
item.InputSchemaJSON = req.InputSchemaJSON
|
||||
item.OutputSchemaJSON = req.OutputSchemaJSON
|
||||
item.ArtifactSchemaJSON = req.ArtifactSchemaJSON
|
||||
item.ActionRefsJSON = req.ActionRefsJSON
|
||||
item.PolicyRefsJSON = req.PolicyRefsJSON
|
||||
item.OntologyBindingJSON = req.OntologyBindingJSON
|
||||
item.State = req.State
|
||||
item.SortOrder = req.SortOrder
|
||||
if err := store.DB.Save(&item).Error; err != nil {
|
||||
web.Fail(c, web.NewBadRequest("更新技能定义失败"))
|
||||
return
|
||||
}
|
||||
web.OK(c, item)
|
||||
}
|
||||
|
||||
func DeleteSkillDefinition(c *gin.Context) {
|
||||
id, ok := parseID(c, "id")
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
var item model.SkillDefinition
|
||||
if err := store.DB.First(&item, id).Error; err != nil {
|
||||
web.Fail(c, web.NewNotFoundError("技能定义不存在"))
|
||||
return
|
||||
}
|
||||
if err := store.DB.Delete(&item).Error; err != nil {
|
||||
web.Fail(c, web.NewBadRequest("删除技能定义失败"))
|
||||
return
|
||||
}
|
||||
web.OK(c, gin.H{"id": id, "deleted": true})
|
||||
}
|
||||
|
||||
func ListActionDefinitions(c *gin.Context) {
|
||||
q := store.DB.Model(&model.ActionDefinition{})
|
||||
if c.Query("state") == "" {
|
||||
q = q.Where("state = ?", "active")
|
||||
} else {
|
||||
q = q.Where("state = ?", c.Query("state"))
|
||||
}
|
||||
var items []model.ActionDefinition
|
||||
if err := q.Order("sort_order ASC, id ASC").Find(&items).Error; err != nil {
|
||||
web.Fail(c, web.NewBadRequest("查询 Action 定义失败"))
|
||||
return
|
||||
}
|
||||
web.OK(c, items)
|
||||
}
|
||||
|
||||
func GetActionDefinitionByKey(c *gin.Context) {
|
||||
key := strings.TrimSpace(c.Param("key"))
|
||||
if key == "" {
|
||||
web.Fail(c, web.NewBadRequest("action key 不能为空"))
|
||||
return
|
||||
}
|
||||
var item model.ActionDefinition
|
||||
if err := store.DB.Where("key = ?", key).First(&item).Error; err != nil {
|
||||
web.Fail(c, web.NewNotFoundError("Action 定义不存在"))
|
||||
return
|
||||
}
|
||||
web.OK(c, item)
|
||||
}
|
||||
|
||||
func CreateActionDefinition(c *gin.Context) {
|
||||
var req actionDefinitionReq
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
web.Fail(c, web.NewBadRequest("请求参数错误"))
|
||||
return
|
||||
}
|
||||
if appErr := validateActionDefinitionReq(&req); appErr != nil {
|
||||
web.Fail(c, appErr)
|
||||
return
|
||||
}
|
||||
item := model.ActionDefinition{
|
||||
Key: req.Key,
|
||||
Label: req.Label,
|
||||
Description: req.Description,
|
||||
ActionType: req.ActionType,
|
||||
ConnectorRef: req.ConnectorRef,
|
||||
InputSchemaJSON: req.InputSchemaJSON,
|
||||
OutputSchemaJSON: req.OutputSchemaJSON,
|
||||
RiskLevel: req.RiskLevel,
|
||||
ApprovalMode: req.ApprovalMode,
|
||||
AuditLevel: req.AuditLevel,
|
||||
ExposedToUser: req.ExposedToUser,
|
||||
OntologyBindingJSON: req.OntologyBindingJSON,
|
||||
State: req.State,
|
||||
SortOrder: req.SortOrder,
|
||||
}
|
||||
if err := store.DB.Create(&item).Error; err != nil {
|
||||
web.Fail(c, web.NewBadRequest("创建 Action 定义失败"))
|
||||
return
|
||||
}
|
||||
web.OK(c, item)
|
||||
}
|
||||
|
||||
func UpdateActionDefinition(c *gin.Context) {
|
||||
id, ok := parseID(c, "id")
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
var item model.ActionDefinition
|
||||
if err := store.DB.First(&item, id).Error; err != nil {
|
||||
web.Fail(c, web.NewNotFoundError("Action 定义不存在"))
|
||||
return
|
||||
}
|
||||
var req actionDefinitionReq
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
web.Fail(c, web.NewBadRequest("请求参数错误"))
|
||||
return
|
||||
}
|
||||
if appErr := validateActionDefinitionReq(&req); appErr != nil {
|
||||
web.Fail(c, appErr)
|
||||
return
|
||||
}
|
||||
item.Key = req.Key
|
||||
item.Label = req.Label
|
||||
item.Description = req.Description
|
||||
item.ActionType = req.ActionType
|
||||
item.ConnectorRef = req.ConnectorRef
|
||||
item.InputSchemaJSON = req.InputSchemaJSON
|
||||
item.OutputSchemaJSON = req.OutputSchemaJSON
|
||||
item.RiskLevel = req.RiskLevel
|
||||
item.ApprovalMode = req.ApprovalMode
|
||||
item.AuditLevel = req.AuditLevel
|
||||
item.ExposedToUser = req.ExposedToUser
|
||||
item.OntologyBindingJSON = req.OntologyBindingJSON
|
||||
item.State = req.State
|
||||
item.SortOrder = req.SortOrder
|
||||
if err := store.DB.Save(&item).Error; err != nil {
|
||||
web.Fail(c, web.NewBadRequest("更新 Action 定义失败"))
|
||||
return
|
||||
}
|
||||
web.OK(c, item)
|
||||
}
|
||||
|
||||
func DeleteActionDefinition(c *gin.Context) {
|
||||
id, ok := parseID(c, "id")
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
var item model.ActionDefinition
|
||||
if err := store.DB.First(&item, id).Error; err != nil {
|
||||
web.Fail(c, web.NewNotFoundError("Action 定义不存在"))
|
||||
return
|
||||
}
|
||||
if err := store.DB.Delete(&item).Error; err != nil {
|
||||
web.Fail(c, web.NewBadRequest("删除 Action 定义失败"))
|
||||
return
|
||||
}
|
||||
web.OK(c, gin.H{"id": id, "deleted": true})
|
||||
}
|
||||
@@ -45,6 +45,8 @@ func RegisterRoutes(r *gin.Engine, cfg *config.Config) {
|
||||
r.GET("/api/specialists/summary", middleware.Auth(cfg), SpecialistSummary)
|
||||
r.GET("/api/skills", middleware.Auth(cfg), ListSkillDefinitions)
|
||||
r.GET("/api/skills/by-key/:key", middleware.Auth(cfg), GetSkillDefinitionByKey)
|
||||
r.GET("/api/apps", middleware.Auth(cfg), ListAppDefinitions)
|
||||
r.GET("/api/apps/by-key/:key", middleware.Auth(cfg), GetAppDefinitionByKey)
|
||||
r.GET("/api/actions", middleware.Auth(cfg), ListActionDefinitions)
|
||||
r.GET("/api/actions/by-key/:key", middleware.Auth(cfg), GetActionDefinitionByKey)
|
||||
r.GET("/api/workbench/overview", middleware.Auth(cfg), WorkbenchOverview)
|
||||
@@ -205,6 +207,9 @@ func RegisterRoutes(r *gin.Engine, cfg *config.Config) {
|
||||
admin.POST("/skills", CreateSkillDefinition)
|
||||
admin.PUT("/skills/:id", UpdateSkillDefinition)
|
||||
admin.DELETE("/skills/:id", DeleteSkillDefinition)
|
||||
admin.POST("/apps", CreateAppDefinition)
|
||||
admin.PUT("/apps/:id", UpdateAppDefinition)
|
||||
admin.DELETE("/apps/:id", DeleteAppDefinition)
|
||||
admin.POST("/actions", CreateActionDefinition)
|
||||
admin.PUT("/actions/:id", UpdateActionDefinition)
|
||||
admin.DELETE("/actions/:id", DeleteActionDefinition)
|
||||
|
||||
@@ -0,0 +1,409 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"eai_agentplatform/backend/internal/model"
|
||||
"eai_agentplatform/backend/internal/store"
|
||||
"eai_agentplatform/backend/internal/web"
|
||||
)
|
||||
|
||||
type skillDefinitionReq struct {
|
||||
Key string `json:"key"`
|
||||
Label string `json:"label"`
|
||||
Description string `json:"description"`
|
||||
ObjectKind string `json:"object_kind"`
|
||||
Source string `json:"source"`
|
||||
ObjectEntryRoute string `json:"object_entry_route"`
|
||||
ExposedToUser bool `json:"exposed_to_user"`
|
||||
StarterPromptsJSON string `json:"starter_prompts_json"`
|
||||
PromptTemplate string `json:"prompt_template"`
|
||||
InputSchemaJSON string `json:"input_schema_json"`
|
||||
OutputSchemaJSON string `json:"output_schema_json"`
|
||||
ArtifactSchemaJSON string `json:"artifact_schema_json"`
|
||||
ActionRefsJSON string `json:"action_refs_json"`
|
||||
PolicyRefsJSON string `json:"policy_refs_json"`
|
||||
OntologyBindingJSON string `json:"ontology_binding_json"`
|
||||
State string `json:"state"`
|
||||
SortOrder int `json:"sort_order"`
|
||||
}
|
||||
|
||||
type actionDefinitionReq struct {
|
||||
Key string `json:"key"`
|
||||
Label string `json:"label"`
|
||||
Description string `json:"description"`
|
||||
ActionType string `json:"action_type"`
|
||||
ConnectorRef string `json:"connector_ref"`
|
||||
InputSchemaJSON string `json:"input_schema_json"`
|
||||
OutputSchemaJSON string `json:"output_schema_json"`
|
||||
RiskLevel string `json:"risk_level"`
|
||||
ApprovalMode string `json:"approval_mode"`
|
||||
AuditLevel string `json:"audit_level"`
|
||||
ExposedToUser bool `json:"exposed_to_user"`
|
||||
OntologyBindingJSON string `json:"ontology_binding_json"`
|
||||
State string `json:"state"`
|
||||
SortOrder int `json:"sort_order"`
|
||||
}
|
||||
|
||||
func normalizeSkillDefinitionReq(req *skillDefinitionReq) {
|
||||
req.Key = strings.TrimSpace(req.Key)
|
||||
req.Label = strings.TrimSpace(req.Label)
|
||||
req.Description = strings.TrimSpace(req.Description)
|
||||
req.ObjectKind = strings.TrimSpace(req.ObjectKind)
|
||||
req.Source = strings.TrimSpace(req.Source)
|
||||
req.ObjectEntryRoute = strings.TrimSpace(req.ObjectEntryRoute)
|
||||
req.StarterPromptsJSON = strings.TrimSpace(req.StarterPromptsJSON)
|
||||
req.PromptTemplate = strings.TrimSpace(req.PromptTemplate)
|
||||
req.InputSchemaJSON = strings.TrimSpace(req.InputSchemaJSON)
|
||||
req.OutputSchemaJSON = strings.TrimSpace(req.OutputSchemaJSON)
|
||||
req.ArtifactSchemaJSON = strings.TrimSpace(req.ArtifactSchemaJSON)
|
||||
req.ActionRefsJSON = strings.TrimSpace(req.ActionRefsJSON)
|
||||
req.PolicyRefsJSON = strings.TrimSpace(req.PolicyRefsJSON)
|
||||
req.OntologyBindingJSON = strings.TrimSpace(req.OntologyBindingJSON)
|
||||
req.State = strings.TrimSpace(req.State)
|
||||
}
|
||||
|
||||
func validateSkillDefinitionReq(req *skillDefinitionReq) *web.AppError {
|
||||
normalizeSkillDefinitionReq(req)
|
||||
if req.Key == "" || req.Label == "" {
|
||||
return web.NewBadRequest("key、label 为必填")
|
||||
}
|
||||
if req.ObjectKind == "" {
|
||||
req.ObjectKind = "skill"
|
||||
}
|
||||
switch req.ObjectKind {
|
||||
case "assistant", "specialist", "skill":
|
||||
default:
|
||||
return web.NewBadRequest("object_kind 只能是 assistant、specialist 或 skill")
|
||||
}
|
||||
if req.Source == "" {
|
||||
req.Source = "eai"
|
||||
}
|
||||
if req.State == "" {
|
||||
req.State = "active"
|
||||
}
|
||||
if req.State != "active" && req.State != "inactive" {
|
||||
return web.NewBadRequest("state 只能是 active 或 inactive")
|
||||
}
|
||||
if !store.ValidateJSONStringArray(req.StarterPromptsJSON) {
|
||||
return web.NewBadRequest("starter_prompts_json 必须是字符串数组")
|
||||
}
|
||||
if !store.ValidateJSONObjectJSON(req.InputSchemaJSON) {
|
||||
return web.NewBadRequest("input_schema_json 必须是 JSON 对象")
|
||||
}
|
||||
if !store.ValidateJSONObjectJSON(req.OutputSchemaJSON) {
|
||||
return web.NewBadRequest("output_schema_json 必须是 JSON 对象")
|
||||
}
|
||||
if !store.ValidateJSONObjectJSON(req.ArtifactSchemaJSON) {
|
||||
return web.NewBadRequest("artifact_schema_json 必须是 JSON 对象")
|
||||
}
|
||||
if !store.ValidateJSONStringArray(req.ActionRefsJSON) {
|
||||
return web.NewBadRequest("action_refs_json 必须是字符串数组")
|
||||
}
|
||||
if !store.ValidateJSONStringArray(req.PolicyRefsJSON) {
|
||||
return web.NewBadRequest("policy_refs_json 必须是字符串数组")
|
||||
}
|
||||
if !store.ValidateJSONObjectJSON(req.OntologyBindingJSON) {
|
||||
return web.NewBadRequest("ontology_binding_json 必须是 JSON 对象")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func normalizeActionDefinitionReq(req *actionDefinitionReq) {
|
||||
req.Key = strings.TrimSpace(req.Key)
|
||||
req.Label = strings.TrimSpace(req.Label)
|
||||
req.Description = strings.TrimSpace(req.Description)
|
||||
req.ActionType = strings.TrimSpace(req.ActionType)
|
||||
req.ConnectorRef = strings.TrimSpace(req.ConnectorRef)
|
||||
req.InputSchemaJSON = strings.TrimSpace(req.InputSchemaJSON)
|
||||
req.OutputSchemaJSON = strings.TrimSpace(req.OutputSchemaJSON)
|
||||
req.RiskLevel = strings.TrimSpace(req.RiskLevel)
|
||||
req.ApprovalMode = strings.TrimSpace(req.ApprovalMode)
|
||||
req.AuditLevel = strings.TrimSpace(req.AuditLevel)
|
||||
req.OntologyBindingJSON = strings.TrimSpace(req.OntologyBindingJSON)
|
||||
req.State = strings.TrimSpace(req.State)
|
||||
}
|
||||
|
||||
func validateActionDefinitionReq(req *actionDefinitionReq) *web.AppError {
|
||||
normalizeActionDefinitionReq(req)
|
||||
if req.Key == "" || req.Label == "" {
|
||||
return web.NewBadRequest("key、label 为必填")
|
||||
}
|
||||
if req.ActionType == "" {
|
||||
req.ActionType = "execution"
|
||||
}
|
||||
if req.RiskLevel == "" {
|
||||
req.RiskLevel = "low"
|
||||
}
|
||||
if req.ApprovalMode == "" {
|
||||
req.ApprovalMode = "not_required"
|
||||
}
|
||||
if req.AuditLevel == "" {
|
||||
req.AuditLevel = "standard"
|
||||
}
|
||||
if req.State == "" {
|
||||
req.State = "active"
|
||||
}
|
||||
if req.State != "active" && req.State != "inactive" {
|
||||
return web.NewBadRequest("state 只能是 active 或 inactive")
|
||||
}
|
||||
if !store.ValidateJSONObjectJSON(req.InputSchemaJSON) {
|
||||
return web.NewBadRequest("input_schema_json 必须是 JSON 对象")
|
||||
}
|
||||
if !store.ValidateJSONObjectJSON(req.OutputSchemaJSON) {
|
||||
return web.NewBadRequest("output_schema_json 必须是 JSON 对象")
|
||||
}
|
||||
if !store.ValidateJSONObjectJSON(req.OntologyBindingJSON) {
|
||||
return web.NewBadRequest("ontology_binding_json 必须是 JSON 对象")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ListSkillDefinitions(c *gin.Context) {
|
||||
q := store.DB.Model(&model.SkillDefinition{})
|
||||
if c.Query("state") == "" {
|
||||
q = q.Where("state = ?", "active")
|
||||
} else {
|
||||
q = q.Where("state = ?", c.Query("state"))
|
||||
}
|
||||
if c.Query("exposed_to_user") != "" {
|
||||
q = q.Where("exposed_to_user = ?", c.Query("exposed_to_user") == "true")
|
||||
}
|
||||
var items []model.SkillDefinition
|
||||
if err := q.Order("sort_order ASC, id ASC").Find(&items).Error; err != nil {
|
||||
web.Fail(c, web.NewBadRequest("查询技能定义失败"))
|
||||
return
|
||||
}
|
||||
web.OK(c, items)
|
||||
}
|
||||
|
||||
func GetSkillDefinitionByKey(c *gin.Context) {
|
||||
key := strings.TrimSpace(c.Param("key"))
|
||||
if key == "" {
|
||||
web.Fail(c, web.NewBadRequest("技能 key 不能为空"))
|
||||
return
|
||||
}
|
||||
var item model.SkillDefinition
|
||||
if err := store.DB.Where("key = ?", key).First(&item).Error; err != nil {
|
||||
web.Fail(c, web.NewNotFoundError("技能定义不存在"))
|
||||
return
|
||||
}
|
||||
web.OK(c, item)
|
||||
}
|
||||
|
||||
func CreateSkillDefinition(c *gin.Context) {
|
||||
var req skillDefinitionReq
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
web.Fail(c, web.NewBadRequest("请求参数错误"))
|
||||
return
|
||||
}
|
||||
if appErr := validateSkillDefinitionReq(&req); appErr != nil {
|
||||
web.Fail(c, appErr)
|
||||
return
|
||||
}
|
||||
item := model.SkillDefinition{
|
||||
Key: req.Key,
|
||||
Label: req.Label,
|
||||
Description: req.Description,
|
||||
ObjectKind: req.ObjectKind,
|
||||
Source: req.Source,
|
||||
ObjectEntryRoute: req.ObjectEntryRoute,
|
||||
ExposedToUser: req.ExposedToUser,
|
||||
StarterPromptsJSON: req.StarterPromptsJSON,
|
||||
PromptTemplate: req.PromptTemplate,
|
||||
InputSchemaJSON: req.InputSchemaJSON,
|
||||
OutputSchemaJSON: req.OutputSchemaJSON,
|
||||
ArtifactSchemaJSON: req.ArtifactSchemaJSON,
|
||||
ActionRefsJSON: req.ActionRefsJSON,
|
||||
PolicyRefsJSON: req.PolicyRefsJSON,
|
||||
OntologyBindingJSON: req.OntologyBindingJSON,
|
||||
State: req.State,
|
||||
SortOrder: req.SortOrder,
|
||||
}
|
||||
if err := store.DB.Create(&item).Error; err != nil {
|
||||
web.Fail(c, web.NewBadRequest("创建技能定义失败"))
|
||||
return
|
||||
}
|
||||
web.OK(c, item)
|
||||
}
|
||||
|
||||
func UpdateSkillDefinition(c *gin.Context) {
|
||||
id, ok := parseID(c, "id")
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
var item model.SkillDefinition
|
||||
if err := store.DB.First(&item, id).Error; err != nil {
|
||||
web.Fail(c, web.NewNotFoundError("技能定义不存在"))
|
||||
return
|
||||
}
|
||||
var req skillDefinitionReq
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
web.Fail(c, web.NewBadRequest("请求参数错误"))
|
||||
return
|
||||
}
|
||||
if appErr := validateSkillDefinitionReq(&req); appErr != nil {
|
||||
web.Fail(c, appErr)
|
||||
return
|
||||
}
|
||||
item.Key = req.Key
|
||||
item.Label = req.Label
|
||||
item.Description = req.Description
|
||||
item.ObjectKind = req.ObjectKind
|
||||
item.Source = req.Source
|
||||
item.ObjectEntryRoute = req.ObjectEntryRoute
|
||||
item.ExposedToUser = req.ExposedToUser
|
||||
item.StarterPromptsJSON = req.StarterPromptsJSON
|
||||
item.PromptTemplate = req.PromptTemplate
|
||||
item.InputSchemaJSON = req.InputSchemaJSON
|
||||
item.OutputSchemaJSON = req.OutputSchemaJSON
|
||||
item.ArtifactSchemaJSON = req.ArtifactSchemaJSON
|
||||
item.ActionRefsJSON = req.ActionRefsJSON
|
||||
item.PolicyRefsJSON = req.PolicyRefsJSON
|
||||
item.OntologyBindingJSON = req.OntologyBindingJSON
|
||||
item.State = req.State
|
||||
item.SortOrder = req.SortOrder
|
||||
if err := store.DB.Save(&item).Error; err != nil {
|
||||
web.Fail(c, web.NewBadRequest("更新技能定义失败"))
|
||||
return
|
||||
}
|
||||
web.OK(c, item)
|
||||
}
|
||||
|
||||
func DeleteSkillDefinition(c *gin.Context) {
|
||||
id, ok := parseID(c, "id")
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
var item model.SkillDefinition
|
||||
if err := store.DB.First(&item, id).Error; err != nil {
|
||||
web.Fail(c, web.NewNotFoundError("技能定义不存在"))
|
||||
return
|
||||
}
|
||||
if err := store.DB.Delete(&item).Error; err != nil {
|
||||
web.Fail(c, web.NewBadRequest("删除技能定义失败"))
|
||||
return
|
||||
}
|
||||
web.OK(c, gin.H{"id": id, "deleted": true})
|
||||
}
|
||||
|
||||
func ListActionDefinitions(c *gin.Context) {
|
||||
q := store.DB.Model(&model.ActionDefinition{})
|
||||
if c.Query("state") == "" {
|
||||
q = q.Where("state = ?", "active")
|
||||
} else {
|
||||
q = q.Where("state = ?", c.Query("state"))
|
||||
}
|
||||
var items []model.ActionDefinition
|
||||
if err := q.Order("sort_order ASC, id ASC").Find(&items).Error; err != nil {
|
||||
web.Fail(c, web.NewBadRequest("查询 Action 定义失败"))
|
||||
return
|
||||
}
|
||||
web.OK(c, items)
|
||||
}
|
||||
|
||||
func GetActionDefinitionByKey(c *gin.Context) {
|
||||
key := strings.TrimSpace(c.Param("key"))
|
||||
if key == "" {
|
||||
web.Fail(c, web.NewBadRequest("action key 不能为空"))
|
||||
return
|
||||
}
|
||||
var item model.ActionDefinition
|
||||
if err := store.DB.Where("key = ?", key).First(&item).Error; err != nil {
|
||||
web.Fail(c, web.NewNotFoundError("Action 定义不存在"))
|
||||
return
|
||||
}
|
||||
web.OK(c, item)
|
||||
}
|
||||
|
||||
func CreateActionDefinition(c *gin.Context) {
|
||||
var req actionDefinitionReq
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
web.Fail(c, web.NewBadRequest("请求参数错误"))
|
||||
return
|
||||
}
|
||||
if appErr := validateActionDefinitionReq(&req); appErr != nil {
|
||||
web.Fail(c, appErr)
|
||||
return
|
||||
}
|
||||
item := model.ActionDefinition{
|
||||
Key: req.Key,
|
||||
Label: req.Label,
|
||||
Description: req.Description,
|
||||
ActionType: req.ActionType,
|
||||
ConnectorRef: req.ConnectorRef,
|
||||
InputSchemaJSON: req.InputSchemaJSON,
|
||||
OutputSchemaJSON: req.OutputSchemaJSON,
|
||||
RiskLevel: req.RiskLevel,
|
||||
ApprovalMode: req.ApprovalMode,
|
||||
AuditLevel: req.AuditLevel,
|
||||
ExposedToUser: req.ExposedToUser,
|
||||
OntologyBindingJSON: req.OntologyBindingJSON,
|
||||
State: req.State,
|
||||
SortOrder: req.SortOrder,
|
||||
}
|
||||
if err := store.DB.Create(&item).Error; err != nil {
|
||||
web.Fail(c, web.NewBadRequest("创建 Action 定义失败"))
|
||||
return
|
||||
}
|
||||
web.OK(c, item)
|
||||
}
|
||||
|
||||
func UpdateActionDefinition(c *gin.Context) {
|
||||
id, ok := parseID(c, "id")
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
var item model.ActionDefinition
|
||||
if err := store.DB.First(&item, id).Error; err != nil {
|
||||
web.Fail(c, web.NewNotFoundError("Action 定义不存在"))
|
||||
return
|
||||
}
|
||||
var req actionDefinitionReq
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
web.Fail(c, web.NewBadRequest("请求参数错误"))
|
||||
return
|
||||
}
|
||||
if appErr := validateActionDefinitionReq(&req); appErr != nil {
|
||||
web.Fail(c, appErr)
|
||||
return
|
||||
}
|
||||
item.Key = req.Key
|
||||
item.Label = req.Label
|
||||
item.Description = req.Description
|
||||
item.ActionType = req.ActionType
|
||||
item.ConnectorRef = req.ConnectorRef
|
||||
item.InputSchemaJSON = req.InputSchemaJSON
|
||||
item.OutputSchemaJSON = req.OutputSchemaJSON
|
||||
item.RiskLevel = req.RiskLevel
|
||||
item.ApprovalMode = req.ApprovalMode
|
||||
item.AuditLevel = req.AuditLevel
|
||||
item.ExposedToUser = req.ExposedToUser
|
||||
item.OntologyBindingJSON = req.OntologyBindingJSON
|
||||
item.State = req.State
|
||||
item.SortOrder = req.SortOrder
|
||||
if err := store.DB.Save(&item).Error; err != nil {
|
||||
web.Fail(c, web.NewBadRequest("更新 Action 定义失败"))
|
||||
return
|
||||
}
|
||||
web.OK(c, item)
|
||||
}
|
||||
|
||||
func DeleteActionDefinition(c *gin.Context) {
|
||||
id, ok := parseID(c, "id")
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
var item model.ActionDefinition
|
||||
if err := store.DB.First(&item, id).Error; err != nil {
|
||||
web.Fail(c, web.NewNotFoundError("Action 定义不存在"))
|
||||
return
|
||||
}
|
||||
if err := store.DB.Delete(&item).Error; err != nil {
|
||||
web.Fail(c, web.NewBadRequest("删除 Action 定义失败"))
|
||||
return
|
||||
}
|
||||
web.OK(c, gin.H{"id": id, "deleted": true})
|
||||
}
|
||||
@@ -110,41 +110,40 @@ func SpecialistSummary(c *gin.Context) {
|
||||
}
|
||||
|
||||
type specialistReq struct {
|
||||
Key string `json:"key"`
|
||||
Label string `json:"label"`
|
||||
DisplayCode string `json:"display_code"`
|
||||
EAILogicCode string `json:"eailogic_code"`
|
||||
Tier string `json:"tier"`
|
||||
WorkerType string `json:"worker_type"`
|
||||
ObjectEntryRoute string `json:"object_entry_route"`
|
||||
Summary string `json:"summary"`
|
||||
RoleCardJSON string `json:"role_card_json"`
|
||||
WorkStatus string `json:"work_status"`
|
||||
RiskLabel string `json:"risk_label"`
|
||||
Color string `json:"color"`
|
||||
Stage string `json:"stage"`
|
||||
Progress int `json:"progress"`
|
||||
MarketTag string `json:"market_tag"`
|
||||
Version string `json:"version"`
|
||||
ConnectorScope string `json:"connector_scope"`
|
||||
PermissionScope string `json:"permission_scope"`
|
||||
ResourceBindings string `json:"resource_bindings"`
|
||||
InfoSources string `json:"info_sources"`
|
||||
BaseSkills string `json:"base_skills"`
|
||||
AIAssistance string `json:"ai_assistance"`
|
||||
GeneratedSkills string `json:"generated_skills"`
|
||||
Key string `json:"key"`
|
||||
Label string `json:"label"`
|
||||
DisplayCode string `json:"display_code"`
|
||||
EAILogicCode string `json:"eailogic_code"`
|
||||
Tier string `json:"tier"`
|
||||
WorkerType string `json:"worker_type"`
|
||||
ObjectEntryRoute string `json:"object_entry_route"`
|
||||
Summary string `json:"summary"`
|
||||
InteractionCardJSON string `json:"interaction_card_json"`
|
||||
WorkStatus string `json:"work_status"`
|
||||
RiskLabel string `json:"risk_label"`
|
||||
Color string `json:"color"`
|
||||
Stage string `json:"stage"`
|
||||
Progress int `json:"progress"`
|
||||
MarketTag string `json:"market_tag"`
|
||||
Version string `json:"version"`
|
||||
ConnectorScope string `json:"connector_scope"`
|
||||
PermissionScope string `json:"permission_scope"`
|
||||
ResourceBindings string `json:"resource_bindings"`
|
||||
InfoSources string `json:"info_sources"`
|
||||
BaseSkills string `json:"base_skills"`
|
||||
AIAssistance string `json:"ai_assistance"`
|
||||
GeneratedSkills string `json:"generated_skills"`
|
||||
// RuleFileMarkdown 岗位说明书正文(Markdown),会话创建时注入 System Prompt
|
||||
RuleFileMarkdown string `json:"rule_file_markdown"`
|
||||
// AllowedSkills 绑定技能 key 的 JSON 数组字符串,顺序即优先级(首个为主技能)。
|
||||
// 元素须在 model.ValidSkillKeys 内;写入前会被规范化成紧凑 JSON。
|
||||
AllowedSkills string `json:"allowed_skills"`
|
||||
InputsRecordsJSON string `json:"inputs_records_json"`
|
||||
LegacySourceRecordsJSON string `json:"source_records_json"`
|
||||
PermissionRecordsJSON string `json:"permission_records_json"`
|
||||
ActionRecordsJSON string `json:"action_records_json"`
|
||||
ResultRecordsJSON string `json:"result_records_json"`
|
||||
State string `json:"state"`
|
||||
SortOrder int `json:"sort_order"`
|
||||
AllowedSkills string `json:"allowed_skills"`
|
||||
InputsRecordsJSON string `json:"inputs_records_json"`
|
||||
PermissionRecordsJSON string `json:"permission_records_json"`
|
||||
ActionRecordsJSON string `json:"action_records_json"`
|
||||
ResultRecordsJSON string `json:"result_records_json"`
|
||||
State string `json:"state"`
|
||||
SortOrder int `json:"sort_order"`
|
||||
}
|
||||
|
||||
func normalizeSpecialistReq(req *specialistReq) {
|
||||
@@ -156,7 +155,7 @@ func normalizeSpecialistReq(req *specialistReq) {
|
||||
req.WorkerType = strings.TrimSpace(req.WorkerType)
|
||||
req.ObjectEntryRoute = strings.TrimSpace(req.ObjectEntryRoute)
|
||||
req.Summary = strings.TrimSpace(req.Summary)
|
||||
req.RoleCardJSON = strings.TrimSpace(req.RoleCardJSON)
|
||||
req.InteractionCardJSON = strings.TrimSpace(req.InteractionCardJSON)
|
||||
req.WorkStatus = strings.TrimSpace(req.WorkStatus)
|
||||
req.RiskLabel = strings.TrimSpace(req.RiskLabel)
|
||||
req.Color = strings.TrimSpace(req.Color)
|
||||
@@ -173,10 +172,6 @@ func normalizeSpecialistReq(req *specialistReq) {
|
||||
req.RuleFileMarkdown = strings.TrimSpace(req.RuleFileMarkdown)
|
||||
req.AllowedSkills = strings.TrimSpace(req.AllowedSkills)
|
||||
req.InputsRecordsJSON = strings.TrimSpace(req.InputsRecordsJSON)
|
||||
req.LegacySourceRecordsJSON = strings.TrimSpace(req.LegacySourceRecordsJSON)
|
||||
if req.InputsRecordsJSON == "" {
|
||||
req.InputsRecordsJSON = req.LegacySourceRecordsJSON
|
||||
}
|
||||
req.PermissionRecordsJSON = strings.TrimSpace(req.PermissionRecordsJSON)
|
||||
req.ActionRecordsJSON = strings.TrimSpace(req.ActionRecordsJSON)
|
||||
req.ResultRecordsJSON = strings.TrimSpace(req.ResultRecordsJSON)
|
||||
@@ -212,8 +207,8 @@ func validateSpecialistReq(req *specialistReq) *web.AppError {
|
||||
if !store.ValidateStructuredRecordsJSON(req.InputsRecordsJSON) {
|
||||
return web.NewBadRequest("inputs_records_json 必须是 JSON 数组")
|
||||
}
|
||||
if !store.ValidateJSONObjectJSON(req.RoleCardJSON) {
|
||||
return web.NewBadRequest("role_card_json 必须是 JSON 对象")
|
||||
if !store.ValidateJSONObjectJSON(req.InteractionCardJSON) {
|
||||
return web.NewBadRequest("interaction_card_json 必须是 JSON 对象")
|
||||
}
|
||||
if !store.ValidateStructuredRecordsJSON(req.PermissionRecordsJSON) {
|
||||
return web.NewBadRequest("permission_records_json 必须是 JSON 数组")
|
||||
@@ -282,7 +277,7 @@ func CreateSpecialist(c *gin.Context) {
|
||||
WorkerType: req.WorkerType,
|
||||
ObjectEntryRoute: req.ObjectEntryRoute,
|
||||
Summary: req.Summary,
|
||||
RoleCardJSON: req.RoleCardJSON,
|
||||
InteractionCardJSON: req.InteractionCardJSON,
|
||||
WorkStatus: req.WorkStatus,
|
||||
RiskLabel: req.RiskLabel,
|
||||
Color: req.Color,
|
||||
@@ -351,7 +346,7 @@ func UpdateSpecialist(c *gin.Context) {
|
||||
item.WorkerType = req.WorkerType
|
||||
item.ObjectEntryRoute = req.ObjectEntryRoute
|
||||
item.Summary = req.Summary
|
||||
item.RoleCardJSON = req.RoleCardJSON
|
||||
item.InteractionCardJSON = req.InteractionCardJSON
|
||||
item.WorkStatus = req.WorkStatus
|
||||
item.RiskLabel = req.RiskLabel
|
||||
item.Color = req.Color
|
||||
|
||||
Reference in New Issue
Block a user