Refactor skill execution and definition handling to support content-based execution and enhance skill definition structure
This commit is contained in:
@@ -1,57 +1,36 @@
|
|||||||
package skills
|
package skills
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
"strings"
|
||||||
"text/template"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"cs-agent/internal/ai"
|
"cs-agent/internal/ai"
|
||||||
"cs-agent/internal/ai/mcps"
|
|
||||||
"cs-agent/internal/pkg/enums"
|
|
||||||
"cs-agent/internal/pkg/errorsx"
|
"cs-agent/internal/pkg/errorsx"
|
||||||
)
|
)
|
||||||
|
|
||||||
type mcpToolExecutionConfig struct {
|
|
||||||
ServerCode string `json:"serverCode"`
|
|
||||||
ToolName string `json:"toolName"`
|
|
||||||
Arguments map[string]string `json:"arguments"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func executeByPlan(ctx context.Context, plan *ExecutionPlan, runtimeCtx RuntimeContext) (string, *ExecutionTrace, error) {
|
func executeByPlan(ctx context.Context, plan *ExecutionPlan, runtimeCtx RuntimeContext) (string, *ExecutionTrace, error) {
|
||||||
if plan == nil || plan.Skill == nil {
|
if plan == nil || plan.Skill == nil {
|
||||||
return "", nil, nil
|
return "", nil, nil
|
||||||
}
|
}
|
||||||
trace := &ExecutionTrace{
|
trace := &ExecutionTrace{
|
||||||
Status: "started",
|
Status: "started",
|
||||||
ExecutionMode: string(plan.Skill.ExecutionMode),
|
ExecutionMode: "content",
|
||||||
}
|
|
||||||
switch plan.Skill.ExecutionMode {
|
|
||||||
case "", enums.SkillExecutionModePromptOnly:
|
|
||||||
replyText, err := executePromptOnly(ctx, plan, runtimeCtx, trace)
|
|
||||||
return replyText, trace, err
|
|
||||||
case enums.SkillExecutionModeMCPTool:
|
|
||||||
replyText, err := executeMCPTool(ctx, plan, runtimeCtx, trace)
|
|
||||||
return replyText, trace, err
|
|
||||||
default:
|
|
||||||
trace.Status = "invalid_execution_mode"
|
|
||||||
return "", trace, errorsx.InvalidParam("Skill执行模式不支持")
|
|
||||||
}
|
}
|
||||||
|
replyText, err := executeContent(ctx, plan, runtimeCtx, trace)
|
||||||
|
return replyText, trace, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func executePromptOnly(ctx context.Context, plan *ExecutionPlan, runtimeCtx RuntimeContext, trace *ExecutionTrace) (string, error) {
|
func executeContent(ctx context.Context, plan *ExecutionPlan, runtimeCtx RuntimeContext, trace *ExecutionTrace) (string, error) {
|
||||||
if plan == nil || plan.Skill == nil {
|
if plan == nil || plan.Skill == nil {
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
if plan.AIConfig == nil {
|
if plan.AIConfig == nil {
|
||||||
return "", errorsx.InvalidParam("Skill 关联的 AI 配置不可用")
|
return "", errorsx.InvalidParam("Skill 关联的 AI 配置不可用")
|
||||||
}
|
}
|
||||||
systemPrompt := strings.TrimSpace(plan.Skill.Prompt)
|
systemPrompt := strings.TrimSpace(plan.Skill.Content)
|
||||||
if systemPrompt == "" {
|
if systemPrompt == "" {
|
||||||
return "", errorsx.InvalidParam("Skill Prompt 不能为空")
|
return "", errorsx.InvalidParam("Skill Content 不能为空")
|
||||||
}
|
}
|
||||||
userPrompt := strings.TrimSpace(runtimeCtx.UserMessage)
|
userPrompt := strings.TrimSpace(runtimeCtx.UserMessage)
|
||||||
if userPrompt == "" {
|
if userPrompt == "" {
|
||||||
@@ -81,168 +60,3 @@ func executePromptOnly(ctx context.Context, plan *ExecutionPlan, runtimeCtx Runt
|
|||||||
}
|
}
|
||||||
return strings.TrimSpace(result.Content), nil
|
return strings.TrimSpace(result.Content), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func executeMCPTool(ctx context.Context, plan *ExecutionPlan, runtimeCtx RuntimeContext, trace *ExecutionTrace) (string, error) {
|
|
||||||
cfg, err := parseMCPToolExecutionConfig(plan.Skill.ExecutionConfig)
|
|
||||||
if err != nil {
|
|
||||||
if trace != nil {
|
|
||||||
trace.Status = "config_error"
|
|
||||||
}
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
arguments, err := buildToolArguments(cfg.Arguments, runtimeCtx)
|
|
||||||
if err != nil {
|
|
||||||
if trace != nil {
|
|
||||||
trace.Status = "argument_error"
|
|
||||||
}
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
mcpTrace := &MCPExecutionTrace{
|
|
||||||
Status: "started",
|
|
||||||
ServerCode: cfg.ServerCode,
|
|
||||||
ToolName: cfg.ToolName,
|
|
||||||
Arguments: arguments,
|
|
||||||
}
|
|
||||||
if trace != nil {
|
|
||||||
trace.MCP = mcpTrace
|
|
||||||
}
|
|
||||||
toolStartedAt := time.Now()
|
|
||||||
toolResult, err := mcps.Runtime.CallTool(ctx, cfg.ServerCode, cfg.ToolName, arguments)
|
|
||||||
mcpTrace.LatencyMs = time.Since(toolStartedAt).Milliseconds()
|
|
||||||
if err != nil {
|
|
||||||
mcpTrace.Status = "error"
|
|
||||||
mcpTrace.Error = err.Error()
|
|
||||||
if trace != nil {
|
|
||||||
trace.Status = "error"
|
|
||||||
}
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
mcpTrace.Status = "ok"
|
|
||||||
mcpTrace.IsError = toolResult.IsError
|
|
||||||
mcpTrace.ContentItemCount = len(toolResult.Content)
|
|
||||||
mcpTrace.HasStructuredContent = toolResult.StructuredContent != nil
|
|
||||||
toolSummary := buildToolSummary(toolResult)
|
|
||||||
mcpTrace.ResultPreview = truncateTraceText(toolSummary, 500)
|
|
||||||
if strings.TrimSpace(toolSummary) == "" {
|
|
||||||
if trace != nil {
|
|
||||||
trace.Status = "empty_tool_result"
|
|
||||||
}
|
|
||||||
return "", errorsx.InvalidParam("MCP工具未返回有效结果")
|
|
||||||
}
|
|
||||||
systemPrompt := strings.TrimSpace(plan.Skill.Prompt)
|
|
||||||
if systemPrompt == "" {
|
|
||||||
systemPrompt = "你是客服技能助手。请依据工具结果准确回答用户问题,不要编造工具结果中不存在的事实。"
|
|
||||||
}
|
|
||||||
userPrompt := fmt.Sprintf("用户问题:%s\n\n工具结果:\n%s", strings.TrimSpace(runtimeCtx.UserMessage), toolSummary)
|
|
||||||
summaryTrace := &PromptTrace{Status: "started"}
|
|
||||||
mcpTrace.SummaryPrompt = summaryTrace
|
|
||||||
summaryStartedAt := time.Now()
|
|
||||||
result, err := ai.LLM.ChatWithConfig(ctx, plan.AIConfig, systemPrompt, userPrompt)
|
|
||||||
summaryTrace.LatencyMs = time.Since(summaryStartedAt).Milliseconds()
|
|
||||||
if err != nil {
|
|
||||||
summaryTrace.Status = "error"
|
|
||||||
summaryTrace.Error = err.Error()
|
|
||||||
if trace != nil {
|
|
||||||
trace.Status = "error"
|
|
||||||
}
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
summaryTrace.Status = "ok"
|
|
||||||
summaryTrace.ModelName = result.ModelName
|
|
||||||
summaryTrace.PromptTokens = result.PromptTokens
|
|
||||||
summaryTrace.CompletionTokens = result.CompletionTokens
|
|
||||||
if trace != nil {
|
|
||||||
trace.Status = "ok"
|
|
||||||
}
|
|
||||||
return strings.TrimSpace(result.Content), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseMCPToolExecutionConfig(raw string) (*mcpToolExecutionConfig, error) {
|
|
||||||
raw = strings.TrimSpace(raw)
|
|
||||||
if raw == "" {
|
|
||||||
return nil, errorsx.InvalidParam("ExecutionConfig不能为空")
|
|
||||||
}
|
|
||||||
cfg := &mcpToolExecutionConfig{}
|
|
||||||
if err := json.Unmarshal([]byte(raw), cfg); err != nil {
|
|
||||||
return nil, errorsx.InvalidParam("ExecutionConfig格式不合法")
|
|
||||||
}
|
|
||||||
if strings.TrimSpace(cfg.ServerCode) == "" {
|
|
||||||
return nil, errorsx.InvalidParam("ExecutionConfig.serverCode不能为空")
|
|
||||||
}
|
|
||||||
if strings.TrimSpace(cfg.ToolName) == "" {
|
|
||||||
return nil, errorsx.InvalidParam("ExecutionConfig.toolName不能为空")
|
|
||||||
}
|
|
||||||
return cfg, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func buildToolArguments(templateArgs map[string]string, runtimeCtx RuntimeContext) (map[string]any, error) {
|
|
||||||
if len(templateArgs) == 0 {
|
|
||||||
return map[string]any{
|
|
||||||
"query": strings.TrimSpace(runtimeCtx.UserMessage),
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
data := map[string]any{
|
|
||||||
"userMessage": strings.TrimSpace(runtimeCtx.UserMessage),
|
|
||||||
"conversationId": runtimeCtx.ConversationID,
|
|
||||||
"aiAgentId": runtimeCtx.AIAgentID,
|
|
||||||
"manualSkillCode": strings.TrimSpace(runtimeCtx.ManualSkillCode),
|
|
||||||
"intentCode": strings.TrimSpace(runtimeCtx.IntentCode),
|
|
||||||
}
|
|
||||||
ret := make(map[string]any, len(templateArgs))
|
|
||||||
for key, value := range templateArgs {
|
|
||||||
rendered, err := renderTemplate(value, data)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errorsx.InvalidParam("ExecutionConfig.arguments模板不合法")
|
|
||||||
}
|
|
||||||
ret[key] = rendered
|
|
||||||
}
|
|
||||||
return ret, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func renderTemplate(raw string, data map[string]any) (string, error) {
|
|
||||||
tpl, err := template.New("skill_arg").Option("missingkey=zero").Parse(raw)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
var buf bytes.Buffer
|
|
||||||
if err := tpl.Execute(&buf, data); err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return strings.TrimSpace(buf.String()), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func buildToolSummary(result *mcps.ToolCallResult) string {
|
|
||||||
if result == nil {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
lines := make([]string, 0, len(result.Content)+2)
|
|
||||||
if result.StructuredContent != nil {
|
|
||||||
if data, err := json.Marshal(result.StructuredContent); err == nil {
|
|
||||||
lines = append(lines, string(data))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, item := range result.Content {
|
|
||||||
if strings.TrimSpace(item.Text) != "" {
|
|
||||||
lines = append(lines, strings.TrimSpace(item.Text))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if item.Data != nil {
|
|
||||||
if data, err := json.Marshal(item.Data); err == nil {
|
|
||||||
lines = append(lines, string(data))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return strings.TrimSpace(strings.Join(lines, "\n"))
|
|
||||||
}
|
|
||||||
|
|
||||||
func truncateTraceText(raw string, limit int) string {
|
|
||||||
raw = strings.TrimSpace(raw)
|
|
||||||
if raw == "" || limit <= 0 {
|
|
||||||
return raw
|
|
||||||
}
|
|
||||||
runes := []rune(raw)
|
|
||||||
if len(runes) <= limit {
|
|
||||||
return raw
|
|
||||||
}
|
|
||||||
return strings.TrimSpace(string(runes[:limit])) + "..."
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ func Execute(ctx context.Context, runtimeCtx RuntimeContext) (*ExecutionResult,
|
|||||||
}
|
}
|
||||||
log := BuildRunLog(runtimeCtx, plan, trace, err)
|
log := BuildRunLog(runtimeCtx, plan, trace, err)
|
||||||
if strings.TrimSpace(replyText) != "" && strings.TrimSpace(log.MatchReason) == "" {
|
if strings.TrimSpace(replyText) != "" && strings.TrimSpace(log.MatchReason) == "" {
|
||||||
log.MatchReason = string(plan.Skill.ExecutionMode)
|
log.MatchReason = "content"
|
||||||
}
|
}
|
||||||
if writeErr := WriteRunLog(log); writeErr != nil && err == nil {
|
if writeErr := WriteRunLog(log); writeErr != nil && err == nil {
|
||||||
err = writeErr
|
err = writeErr
|
||||||
|
|||||||
@@ -1,29 +1,38 @@
|
|||||||
package builders
|
package builders
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
"cs-agent/internal/models"
|
"cs-agent/internal/models"
|
||||||
"cs-agent/internal/pkg/dto/response"
|
"cs-agent/internal/pkg/dto/response"
|
||||||
"cs-agent/internal/pkg/enums"
|
"cs-agent/internal/pkg/enums"
|
||||||
)
|
)
|
||||||
|
|
||||||
func BuildSkillDefinitionResponse(item *models.SkillDefinition) response.SkillDefinitionResponse {
|
func BuildSkillDefinitionResponse(item *models.SkillDefinition) response.SkillDefinitionResponse {
|
||||||
|
examples := make([]string, 0)
|
||||||
|
if raw := item.Examples; raw != "" {
|
||||||
|
_ = json.Unmarshal([]byte(raw), &examples)
|
||||||
|
}
|
||||||
|
allowedToolCodes := make([]string, 0)
|
||||||
|
if raw := item.AllowedToolCodes; raw != "" {
|
||||||
|
_ = json.Unmarshal([]byte(raw), &allowedToolCodes)
|
||||||
|
}
|
||||||
return response.SkillDefinitionResponse{
|
return response.SkillDefinitionResponse{
|
||||||
ID: item.ID,
|
ID: item.ID,
|
||||||
Code: item.Code,
|
Code: item.Code,
|
||||||
Name: item.Name,
|
Name: item.Name,
|
||||||
Description: item.Description,
|
Description: item.Description,
|
||||||
Prompt: item.Prompt,
|
Content: item.Content,
|
||||||
ExecutionMode: string(item.ExecutionMode),
|
Examples: examples,
|
||||||
ExecutionModeName: enums.GetSkillExecutionModeLabel(item.ExecutionMode),
|
AllowedToolCodes: allowedToolCodes,
|
||||||
ExecutionConfig: item.ExecutionConfig,
|
Priority: item.Priority,
|
||||||
Priority: item.Priority,
|
Status: int(item.Status),
|
||||||
Status: int(item.Status),
|
StatusName: getSkillStatusName(item.Status),
|
||||||
StatusName: getSkillStatusName(item.Status),
|
Remark: item.Remark,
|
||||||
Remark: item.Remark,
|
CreatedAt: item.CreatedAt,
|
||||||
CreatedAt: item.CreatedAt,
|
UpdatedAt: item.UpdatedAt,
|
||||||
UpdatedAt: item.UpdatedAt,
|
CreateUserName: item.CreateUserName,
|
||||||
CreateUserName: item.CreateUserName,
|
UpdateUserName: item.UpdateUserName,
|
||||||
UpdateUserName: item.UpdateUserName,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -88,16 +88,19 @@ func (c *SkillDefinitionController) PostCreate() *web.JsonResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
item := &models.SkillDefinition{
|
item := &models.SkillDefinition{
|
||||||
Code: strings.TrimSpace(req.Code),
|
Code: strings.TrimSpace(req.Code),
|
||||||
Name: strings.TrimSpace(req.Name),
|
Name: strings.TrimSpace(req.Name),
|
||||||
Description: strings.TrimSpace(req.Description),
|
Description: strings.TrimSpace(req.Description),
|
||||||
Prompt: strings.TrimSpace(req.Prompt),
|
Content: strings.TrimSpace(req.Content),
|
||||||
ExecutionMode: normalizeExecutionMode(req.ExecutionMode),
|
Examples: mustMarshalJSONStringArray(req.Examples),
|
||||||
ExecutionConfig: normalizeExecutionConfig(req.ExecutionConfig),
|
AllowedToolCodes: mustMarshalJSONStringArray(req.AllowedToolCodes),
|
||||||
Priority: 0,
|
Priority: normalizeSkillPriority(req.Priority),
|
||||||
Status: enums.StatusOk,
|
Status: enums.StatusOk,
|
||||||
Remark: strings.TrimSpace(req.Remark),
|
Remark: strings.TrimSpace(req.Remark),
|
||||||
AuditFields: utils.BuildAuditFields(operator),
|
AuditFields: utils.BuildAuditFields(operator),
|
||||||
|
}
|
||||||
|
if item.Priority <= 0 {
|
||||||
|
item.Priority = services.SkillDefinitionService.NextPriority()
|
||||||
}
|
}
|
||||||
if err := services.SkillDefinitionService.Create(item); err != nil {
|
if err := services.SkillDefinitionService.Create(item); err != nil {
|
||||||
return web.JsonError(err)
|
return web.JsonError(err)
|
||||||
@@ -132,16 +135,17 @@ func (c *SkillDefinitionController) PostUpdate() *web.JsonResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err := services.SkillDefinitionService.Updates(req.ID, map[string]any{
|
if err := services.SkillDefinitionService.Updates(req.ID, map[string]any{
|
||||||
"code": strings.TrimSpace(req.Code),
|
"code": strings.TrimSpace(req.Code),
|
||||||
"name": strings.TrimSpace(req.Name),
|
"name": strings.TrimSpace(req.Name),
|
||||||
"description": strings.TrimSpace(req.Description),
|
"description": strings.TrimSpace(req.Description),
|
||||||
"prompt": strings.TrimSpace(req.Prompt),
|
"content": strings.TrimSpace(req.Content),
|
||||||
"execution_mode": normalizeExecutionMode(req.ExecutionMode),
|
"examples": mustMarshalJSONStringArray(req.Examples),
|
||||||
"execution_config": normalizeExecutionConfig(req.ExecutionConfig),
|
"allowed_tool_codes": mustMarshalJSONStringArray(req.AllowedToolCodes),
|
||||||
"remark": strings.TrimSpace(req.Remark),
|
"priority": resolveSkillPriorityForUpdate(req.Priority, item.Priority),
|
||||||
"update_user_id": operator.UserID,
|
"remark": strings.TrimSpace(req.Remark),
|
||||||
"update_user_name": operator.Username,
|
"update_user_id": operator.UserID,
|
||||||
"updated_at": time.Now(),
|
"update_user_name": operator.Username,
|
||||||
|
"updated_at": time.Now(),
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return web.JsonError(err)
|
return web.JsonError(err)
|
||||||
}
|
}
|
||||||
@@ -240,41 +244,65 @@ func (c *SkillDefinitionController) PostDebug_run() *web.JsonResult {
|
|||||||
func validateSkillDefinitionRequest(req request.CreateSkillDefinitionRequest) error {
|
func validateSkillDefinitionRequest(req request.CreateSkillDefinitionRequest) error {
|
||||||
code := strings.TrimSpace(req.Code)
|
code := strings.TrimSpace(req.Code)
|
||||||
name := strings.TrimSpace(req.Name)
|
name := strings.TrimSpace(req.Name)
|
||||||
prompt := strings.TrimSpace(req.Prompt)
|
content := strings.TrimSpace(req.Content)
|
||||||
if code == "" {
|
if code == "" {
|
||||||
return errorsx.InvalidParam("Skill 编码不能为空")
|
return errorsx.InvalidParam("Skill 编码不能为空")
|
||||||
}
|
}
|
||||||
if name == "" {
|
if name == "" {
|
||||||
return errorsx.InvalidParam("Skill 名称不能为空")
|
return errorsx.InvalidParam("Skill 名称不能为空")
|
||||||
}
|
}
|
||||||
mode := normalizeExecutionMode(req.ExecutionMode)
|
if content == "" {
|
||||||
if prompt == "" {
|
return errorsx.InvalidParam("Content 不能为空")
|
||||||
return errorsx.InvalidParam("Prompt 不能为空")
|
|
||||||
}
|
}
|
||||||
switch mode {
|
if _, err := normalizeJSONStringArray(req.Examples); err != nil {
|
||||||
case enums.SkillExecutionModePromptOnly:
|
return err
|
||||||
case enums.SkillExecutionModeMCPTool:
|
}
|
||||||
configText := strings.TrimSpace(req.ExecutionConfig)
|
if _, err := normalizeJSONStringArray(req.AllowedToolCodes); err != nil {
|
||||||
if configText == "" {
|
return err
|
||||||
return errorsx.InvalidParam("MCP工具模式必须填写ExecutionConfig")
|
|
||||||
}
|
|
||||||
var payload map[string]any
|
|
||||||
if err := json.Unmarshal([]byte(configText), &payload); err != nil {
|
|
||||||
return errorsx.InvalidParam("ExecutionConfig 必须是合法JSON")
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return errorsx.InvalidParam("Skill 执行模式不合法")
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func normalizeExecutionMode(mode enums.SkillExecutionMode) enums.SkillExecutionMode {
|
func normalizeSkillPriority(priority int) int {
|
||||||
if mode == "" {
|
if priority < 0 {
|
||||||
return enums.SkillExecutionModePromptOnly
|
return 0
|
||||||
}
|
}
|
||||||
return mode
|
return priority
|
||||||
}
|
}
|
||||||
|
|
||||||
func normalizeExecutionConfig(raw string) string {
|
func resolveSkillPriorityForUpdate(input, current int) int {
|
||||||
return strings.TrimSpace(raw)
|
input = normalizeSkillPriority(input)
|
||||||
|
if input <= 0 {
|
||||||
|
return current
|
||||||
|
}
|
||||||
|
return input
|
||||||
|
}
|
||||||
|
|
||||||
|
func normalizeJSONStringArray(input []string) ([]string, error) {
|
||||||
|
ret := make([]string, 0, len(input))
|
||||||
|
seen := make(map[string]struct{})
|
||||||
|
for _, item := range input {
|
||||||
|
item = strings.TrimSpace(item)
|
||||||
|
if item == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if _, exists := seen[item]; exists {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
seen[item] = struct{}{}
|
||||||
|
ret = append(ret, item)
|
||||||
|
}
|
||||||
|
return ret, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func mustMarshalJSONStringArray(input []string) string {
|
||||||
|
items, _ := normalizeJSONStringArray(input)
|
||||||
|
if len(items) == 0 {
|
||||||
|
return "[]"
|
||||||
|
}
|
||||||
|
buf, err := json.Marshal(items)
|
||||||
|
if err != nil {
|
||||||
|
return "[]"
|
||||||
|
}
|
||||||
|
return string(buf)
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-10
@@ -906,16 +906,16 @@ type KnowledgeFeedback struct {
|
|||||||
|
|
||||||
// SkillDefinition 表示可由后台配置并参与运行时路由的 Skill 定义。
|
// SkillDefinition 表示可由后台配置并参与运行时路由的 Skill 定义。
|
||||||
type SkillDefinition struct {
|
type SkillDefinition struct {
|
||||||
ID int64 `gorm:"primaryKey;autoIncrement"` // ID 为 Skill 主键。
|
ID int64 `gorm:"primaryKey;autoIncrement"` // ID 为 Skill 主键。
|
||||||
Code string `gorm:"type:varchar(100);not null;default:'';uniqueIndex"` // Code 为 Skill 的稳定唯一编码,供程序内部引用和路由判断使用,例如 refund_skill。
|
Code string `gorm:"type:varchar(100);not null;default:'';uniqueIndex"` // Code 为 Skill 的稳定唯一编码,供程序内部引用和路由判断使用,例如 refund_skill。
|
||||||
Name string `gorm:"type:varchar(100);not null;default:'';index"` // Name 为 Skill 的展示名称,用于后台列表、配置页和人工选择场景。
|
Name string `gorm:"type:varchar(100);not null;default:'';index"` // Name 为 Skill 的展示名称,用于后台列表、配置页和人工选择场景。
|
||||||
Description string `gorm:"type:varchar(255);not null;default:''"` // Description 为 Skill 的简要说明,用于描述该 Skill 的适用场景和职责边界。
|
Description string `gorm:"type:varchar(255);not null;default:''"` // Description 为 Skill 的简要说明,用于描述该 Skill 的适用场景和职责边界。
|
||||||
Prompt string `gorm:"type:longtext"` // Prompt 为 Skill 的核心提示词,在命中后注入模型上下文参与执行。
|
Content string `gorm:"type:longtext"` // Content 为 Skill 的主体文档,使用 Markdown 编写,供 Agent 理解任务目标、步骤和工具使用要求。
|
||||||
ExecutionMode enums.SkillExecutionMode `gorm:"type:varchar(30);not null;default:'prompt_only'"` // ExecutionMode 为 Skill 执行模式。
|
Examples string `gorm:"type:text"` // Examples 为示例问法 JSON 数组字符串。
|
||||||
ExecutionConfig string `gorm:"type:text"` // ExecutionConfig 为 Skill 执行配置JSON。
|
AllowedToolCodes string `gorm:"type:text"` // AllowedToolCodes 为允许使用的工具编码 JSON 数组字符串。
|
||||||
Priority int `gorm:"type:int;not null;default:0;index"` // Priority 为 Skill 命中冲突时的优先级,数值越大优先级越高。
|
Priority int `gorm:"type:int;not null;default:0;index"` // Priority 为 Skill 命中冲突时的优先级,数值越大优先级越高。
|
||||||
Status enums.Status `gorm:"type:int;not null;default:0;index"` // Status 为 Skill 当前状态,使用全局通用状态:0启用 1禁用 2删除。
|
Status enums.Status `gorm:"type:int;not null;default:0;index"` // Status 为 Skill 当前状态,使用全局通用状态:0启用 1禁用 2删除。
|
||||||
Remark string `gorm:"type:text"` // Remark 为后台备注,用于记录配置说明、维护信息或内部协作信息。
|
Remark string `gorm:"type:text"` // Remark 为后台备注,用于记录配置说明、维护信息或内部协作信息。
|
||||||
AuditFields
|
AuditFields
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
package request
|
package request
|
||||||
|
|
||||||
import "cs-agent/internal/pkg/enums"
|
|
||||||
|
|
||||||
type SkillDefinitionListRequest struct {
|
type SkillDefinitionListRequest struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Code string `json:"code"`
|
Code string `json:"code"`
|
||||||
@@ -9,13 +7,14 @@ type SkillDefinitionListRequest struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type CreateSkillDefinitionRequest struct {
|
type CreateSkillDefinitionRequest struct {
|
||||||
Code string `json:"code"`
|
Code string `json:"code"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
Prompt string `json:"prompt"`
|
Content string `json:"content"`
|
||||||
ExecutionMode enums.SkillExecutionMode `json:"executionMode"`
|
Examples []string `json:"examples"`
|
||||||
ExecutionConfig string `json:"executionConfig"`
|
AllowedToolCodes []string `json:"allowedToolCodes"`
|
||||||
Remark string `json:"remark"`
|
Priority int `json:"priority"`
|
||||||
|
Remark string `json:"remark"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type UpdateSkillDefinitionRequest struct {
|
type UpdateSkillDefinitionRequest struct {
|
||||||
|
|||||||
@@ -3,22 +3,21 @@ package response
|
|||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
type SkillDefinitionResponse struct {
|
type SkillDefinitionResponse struct {
|
||||||
ID int64 `json:"id"`
|
ID int64 `json:"id"`
|
||||||
Code string `json:"code"`
|
Code string `json:"code"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
Prompt string `json:"prompt"`
|
Content string `json:"content"`
|
||||||
ExecutionMode string `json:"executionMode"`
|
Examples []string `json:"examples"`
|
||||||
ExecutionModeName string `json:"executionModeName"`
|
AllowedToolCodes []string `json:"allowedToolCodes"`
|
||||||
ExecutionConfig string `json:"executionConfig"`
|
Priority int `json:"priority"`
|
||||||
Priority int `json:"priority"`
|
Status int `json:"status"`
|
||||||
Status int `json:"status"`
|
StatusName string `json:"statusName"`
|
||||||
StatusName string `json:"statusName"`
|
Remark string `json:"remark"`
|
||||||
Remark string `json:"remark"`
|
CreatedAt time.Time `json:"createdAt"`
|
||||||
CreatedAt time.Time `json:"createdAt"`
|
UpdatedAt time.Time `json:"updatedAt"`
|
||||||
UpdatedAt time.Time `json:"updatedAt"`
|
CreateUserName string `json:"createUserName"`
|
||||||
CreateUserName string `json:"createUserName"`
|
UpdateUserName string `json:"updateUserName"`
|
||||||
UpdateUserName string `json:"updateUserName"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type SkillDebugRunResponse struct {
|
type SkillDebugRunResponse struct {
|
||||||
|
|||||||
Reference in New Issue
Block a user