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,38 @@
|
||||
package model
|
||||
|
||||
import "time"
|
||||
|
||||
// AppDefinition 面向用户的一键应用目录定义。
|
||||
// 它是“成品入口”这一层:决定应用怎么展示、默认挂哪个专员/技能、打开后走哪条路。
|
||||
type AppDefinition struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
Key string `gorm:"size:64;uniqueIndex;not null" json:"key"`
|
||||
Label string `gorm:"size:128;not null" json:"label"`
|
||||
DisplayCode string `gorm:"column:display_code;size:16;default:'';index" json:"display_code"`
|
||||
EAILogicCode string `gorm:"column:eailogic_code;size:32;default:'';index" json:"eailogic_code"`
|
||||
Badge string `gorm:"size:32;default:''" json:"badge"`
|
||||
Kind string `gorm:"size:64;default:''" json:"kind"`
|
||||
MarketTag string `gorm:"column:market_tag;size:32;default:'';index" json:"market_tag"`
|
||||
WorkerType string `gorm:"size:16;default:'';index" json:"worker_type"`
|
||||
Tier string `gorm:"size:16;default:'';index" json:"tier"`
|
||||
Source string `gorm:"size:32;not null;default:eai;index" json:"source"` // eai / custom / imported
|
||||
Color string `gorm:"size:32;default:''" json:"color"`
|
||||
IconText string `gorm:"column:icon_text;size:16;default:''" json:"icon_text"`
|
||||
CoverTone string `gorm:"column:cover_tone;type:text" json:"cover_tone"`
|
||||
Summary string `gorm:"type:text" json:"summary"`
|
||||
Description string `gorm:"type:text" json:"description"`
|
||||
OpenRoute string `gorm:"column:open_route;size:256;default:''" json:"open_route"`
|
||||
SpecialistKey string `gorm:"column:specialist_key;size:64;default:'';index" json:"specialist_key"`
|
||||
SkillKey string `gorm:"column:skill_key;size:64;default:'';index" json:"skill_key"`
|
||||
DefaultPrompt string `gorm:"column:default_prompt;type:text" json:"default_prompt"`
|
||||
PromptsJSON string `gorm:"column:prompts_json;type:text" json:"prompts_json"`
|
||||
TagsJSON string `gorm:"column:tags_json;type:text" json:"tags_json"`
|
||||
InstallState string `gorm:"column:install_state;size:16;not null;default:installed;index" json:"install_state"`
|
||||
ExposedToUser bool `gorm:"column:exposed_to_user;not null;default:true;index" json:"exposed_to_user"`
|
||||
State string `gorm:"size:16;not null;default:active;index" json:"state"` // active / inactive
|
||||
SortOrder int `gorm:"not null;default:0;index" json:"sort_order"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
func (AppDefinition) TableName() string { return "app_definition" }
|
||||
@@ -4,29 +4,28 @@ import "time"
|
||||
|
||||
// SkillDefinition 对外暴露的任务级能力定义。
|
||||
type SkillDefinition struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
Key string `gorm:"size:64;uniqueIndex;not null" json:"key"`
|
||||
Label string `gorm:"size:128;not null" json:"label"`
|
||||
DisplayCode string `gorm:"column:display_code;size:16;default:'';index" json:"display_code"`
|
||||
EAILogicCode string `gorm:"column:eailogic_code;size:32;default:'';index" json:"eailogic_code"`
|
||||
Description string `gorm:"type:text" json:"description"`
|
||||
RoleKind string `gorm:"size:32;not null;default:skill;index" json:"role_kind"` // assistant / specialist / skill
|
||||
Source string `gorm:"size:32;not null;default:eai;index" json:"source"` // eai / custom
|
||||
ObjectEntryRoute string `gorm:"column:object_entry_route;size:128;default:''" json:"object_entry_route"`
|
||||
LegacyObjectEntryRoute string `gorm:"column:legacy_object_entry_route;size:128;default:''" json:"legacy_object_entry_route"`
|
||||
ExposedToUser bool `gorm:"not null;default:true;index" json:"exposed_to_user"`
|
||||
StarterPromptsJSON string `gorm:"type:text" json:"starter_prompts_json"`
|
||||
PromptTemplate string `gorm:"type:text" json:"prompt_template"`
|
||||
InputSchemaJSON string `gorm:"type:text" json:"input_schema_json"`
|
||||
OutputSchemaJSON string `gorm:"type:text" json:"output_schema_json"`
|
||||
ArtifactSchemaJSON string `gorm:"type:text" json:"artifact_schema_json"`
|
||||
ActionRefsJSON string `gorm:"type:text" json:"action_refs_json"`
|
||||
PolicyRefsJSON string `gorm:"type:text" json:"policy_refs_json"`
|
||||
OntologyBindingJSON string `gorm:"type:text" json:"ontology_binding_json"`
|
||||
State string `gorm:"size:16;not null;default:active;index" json:"state"`
|
||||
SortOrder int `gorm:"not null;default:0;index" json:"sort_order"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
Key string `gorm:"size:64;uniqueIndex;not null" json:"key"`
|
||||
Label string `gorm:"size:128;not null" json:"label"`
|
||||
DisplayCode string `gorm:"column:display_code;size:16;default:'';index" json:"display_code"`
|
||||
EAILogicCode string `gorm:"column:eailogic_code;size:32;default:'';index" json:"eailogic_code"`
|
||||
Description string `gorm:"type:text" json:"description"`
|
||||
ObjectKind string `gorm:"column:object_kind;size:32;not null;default:skill;index" json:"object_kind"` // assistant / specialist / skill
|
||||
Source string `gorm:"size:32;not null;default:eai;index" json:"source"` // eai / custom
|
||||
ObjectEntryRoute string `gorm:"column:object_entry_route;size:128;default:''" json:"object_entry_route"`
|
||||
ExposedToUser bool `gorm:"not null;default:true;index" json:"exposed_to_user"`
|
||||
StarterPromptsJSON string `gorm:"type:text" json:"starter_prompts_json"`
|
||||
PromptTemplate string `gorm:"type:text" json:"prompt_template"`
|
||||
InputSchemaJSON string `gorm:"type:text" json:"input_schema_json"`
|
||||
OutputSchemaJSON string `gorm:"type:text" json:"output_schema_json"`
|
||||
ArtifactSchemaJSON string `gorm:"type:text" json:"artifact_schema_json"`
|
||||
ActionRefsJSON string `gorm:"type:text" json:"action_refs_json"`
|
||||
PolicyRefsJSON string `gorm:"type:text" json:"policy_refs_json"`
|
||||
OntologyBindingJSON string `gorm:"type:text" json:"ontology_binding_json"`
|
||||
State string `gorm:"size:16;not null;default:active;index" json:"state"`
|
||||
SortOrder int `gorm:"not null;default:0;index" json:"sort_order"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
func (SkillDefinition) TableName() string { return "skill_definition" }
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
|
||||
// ValidSkillKeys 技能 key 全集,用于校验 Specialist.AllowedSkills。
|
||||
//
|
||||
// 权威来源是前端 frontend/src/config/workbench.js 的 availableSkills ——
|
||||
// 权威来源是前端 frontend/src/config/workbench.js 的 staticSkillCatalog ——
|
||||
// 技能实现仍归前端,后端只持有 key 清单,用于录入时挡住拼写错误。
|
||||
// 两个清单的一致性由 skill_keys_test.go 守着,改动任一侧都会让测试失败。
|
||||
//
|
||||
|
||||
@@ -12,11 +12,11 @@ import (
|
||||
// workbenchJSRelPath 前端技能目录的相对路径(相对本包目录)。
|
||||
const workbenchJSRelPath = "../../../frontend/src/config/workbench.js"
|
||||
|
||||
// createSkillDefinitionRe 抓 availableSkills 数组里每个 createSkillDefinition 的字面量 key。
|
||||
// createSkillDefinitionRe 抓 staticSkillCatalog 数组里每个 createSkillDefinition 的字面量 key。
|
||||
// 依赖 workbench.js 里「createSkillDefinition({ 紧跟 key: '…'」这一写法。
|
||||
var createSkillDefinitionRe = regexp.MustCompile(`createSkillDefinition\(\{\s*key:\s*'([^']+)'`)
|
||||
|
||||
// TestValidSkillKeysMatchFrontend 守住 backend 的 ValidSkillKeys 与前端 availableSkills 一致。
|
||||
// TestValidSkillKeysMatchFrontend 守住 backend 的 ValidSkillKeys 与前端 staticSkillCatalog 一致。
|
||||
//
|
||||
// 这两份清单天然会漂移:技能实现在前端,后端只持有 key 做录入校验。任何一侧增删技能
|
||||
// 而忘了另一侧,这里就会红——这正是本测试存在的唯一理由。
|
||||
@@ -54,11 +54,11 @@ func TestValidSkillKeysMatchFrontend(t *testing.T) {
|
||||
sort.Strings(onlyFrontend)
|
||||
|
||||
if len(onlyBackend) > 0 {
|
||||
t.Errorf("ValidSkillKeys 里有、前端 availableSkills 里没有的 key(后端多写或前端已删):\n %s",
|
||||
t.Errorf("ValidSkillKeys 里有、前端 staticSkillCatalog 里没有的 key(后端多写或前端已删):\n %s",
|
||||
strings.Join(onlyBackend, "\n "))
|
||||
}
|
||||
if len(onlyFrontend) > 0 {
|
||||
t.Errorf("前端 availableSkills 里有、ValidSkillKeys 里没有的 key(新增技能后忘了补后端清单):\n %s",
|
||||
t.Errorf("前端 staticSkillCatalog 里有、ValidSkillKeys 里没有的 key(新增技能后忘了补后端清单):\n %s",
|
||||
strings.Join(onlyFrontend, "\n "))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,39 +4,39 @@ import "time"
|
||||
|
||||
// Specialist 数字员工专员目录
|
||||
type Specialist struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
Key string `gorm:"size:64;uniqueIndex;not null" json:"key"`
|
||||
Label string `gorm:"size:128;not null" json:"label"`
|
||||
DisplayCode string `gorm:"column:display_code;size:16;default:'';index" json:"display_code"`
|
||||
EAILogicCode string `gorm:"column:eailogic_code;size:32;default:'';index" json:"eailogic_code"`
|
||||
Tier string `gorm:"size:16;not null;index" json:"tier"` // generic / industry
|
||||
WorkerType string `gorm:"size:16;not null;default:dw;index" json:"worker_type"`
|
||||
ObjectEntryRoute string `gorm:"column:object_entry_route;size:128;not null;default:''" json:"object_entry_route"`
|
||||
Summary string `gorm:"type:text" json:"summary"`
|
||||
RoleCardJSON string `gorm:"type:text" json:"role_card_json"`
|
||||
WorkStatus string `gorm:"size:64;default:''" json:"work_status"`
|
||||
RiskLabel string `gorm:"size:64;default:''" json:"risk_label"`
|
||||
Color string `gorm:"size:16;default:''" json:"color"`
|
||||
Stage string `gorm:"size:64;default:''" json:"stage"`
|
||||
Progress int `gorm:"not null;default:0" json:"progress"`
|
||||
MarketTag string `gorm:"size:32;not null;default:installed;index" json:"market_tag"` // 已安装 / 可升级 / 试用
|
||||
Version string `gorm:"size:32;default:''" json:"version"`
|
||||
ConnectorScope string `gorm:"type:text" json:"connector_scope"`
|
||||
PermissionScope string `gorm:"type:text" json:"permission_scope"`
|
||||
ResourceBindings string `gorm:"type:text" json:"resource_bindings"`
|
||||
InfoSources string `gorm:"type:text" json:"info_sources"`
|
||||
BaseSkills string `gorm:"type:text" json:"base_skills"`
|
||||
AIAssistance string `gorm:"type:text" json:"ai_assistance"`
|
||||
GeneratedSkills string `gorm:"type:text" json:"generated_skills"`
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
Key string `gorm:"size:64;uniqueIndex;not null" json:"key"`
|
||||
Label string `gorm:"size:128;not null" json:"label"`
|
||||
DisplayCode string `gorm:"column:display_code;size:16;default:'';index" json:"display_code"`
|
||||
EAILogicCode string `gorm:"column:eailogic_code;size:32;default:'';index" json:"eailogic_code"`
|
||||
Tier string `gorm:"size:16;not null;index" json:"tier"` // generic / industry
|
||||
WorkerType string `gorm:"size:16;not null;default:dw;index" json:"worker_type"`
|
||||
ObjectEntryRoute string `gorm:"column:object_entry_route;size:128;not null;default:''" json:"object_entry_route"`
|
||||
Summary string `gorm:"type:text" json:"summary"`
|
||||
InteractionCardJSON string `gorm:"column:interaction_card_json;type:text" json:"interaction_card_json"`
|
||||
WorkStatus string `gorm:"size:64;default:''" json:"work_status"`
|
||||
RiskLabel string `gorm:"size:64;default:''" json:"risk_label"`
|
||||
Color string `gorm:"size:16;default:''" json:"color"`
|
||||
Stage string `gorm:"size:64;default:''" json:"stage"`
|
||||
Progress int `gorm:"not null;default:0" json:"progress"`
|
||||
MarketTag string `gorm:"size:32;not null;default:installed;index" json:"market_tag"` // 已安装 / 可升级 / 试用
|
||||
Version string `gorm:"size:32;default:''" json:"version"`
|
||||
ConnectorScope string `gorm:"type:text" json:"connector_scope"`
|
||||
PermissionScope string `gorm:"type:text" json:"permission_scope"`
|
||||
ResourceBindings string `gorm:"type:text" json:"resource_bindings"`
|
||||
InfoSources string `gorm:"type:text" json:"info_sources"`
|
||||
BaseSkills string `gorm:"type:text" json:"base_skills"`
|
||||
AIAssistance string `gorm:"type:text" json:"ai_assistance"`
|
||||
GeneratedSkills string `gorm:"type:text" json:"generated_skills"`
|
||||
// RuleFileMarkdown 岗位说明书正文(Markdown 全文)。
|
||||
// 会话创建时注入 System Prompt,决定这个专员怎么说话、怎么推进、什么时候调用哪个技能。
|
||||
// 参考 AionCore builtin-assistants 的 rule_file;命名对齐 SY23。
|
||||
RuleFileMarkdown string `gorm:"type:text" json:"rule_file_markdown"`
|
||||
// AllowedSkills 绑定技能 key 列表,JSON 字符串数组,顺序即优先级(首个为主技能)。
|
||||
// 元素取值须通过 model.ValidSkillKeys 校验,对齐前端 availableSkills[].key。
|
||||
// 元素取值须通过 model.ValidSkillKeys 校验,对齐前端 staticSkillCatalog[].key。
|
||||
// 字段名对齐 SY22 §6.1 对象 manifest 的 allowed_skills。
|
||||
AllowedSkills string `gorm:"type:text" json:"allowed_skills"`
|
||||
InputsRecordsJSON string `gorm:"column:source_records_json;type:text" json:"inputs_records_json"`
|
||||
InputsRecordsJSON string `gorm:"column:inputs_records_json;type:text" json:"inputs_records_json"`
|
||||
PermissionRecordsJSON string `gorm:"type:text" json:"permission_records_json"`
|
||||
ActionRecordsJSON string `gorm:"type:text" json:"action_records_json"`
|
||||
ResultRecordsJSON string `gorm:"type:text" json:"result_records_json"`
|
||||
|
||||
Reference in New Issue
Block a user