Refactor skill handling and improve runtime trace capabilities

- Removed the selectSkill method from prepareService and adjusted related logic in the Run method of Service.
- Updated tool catalog to parse agent allowed tool codes directly.
- Simplified Request and RunInput structures by removing unnecessary fields.
- Enhanced the RuntimeTraceCollector to manage skill activation and visibility.
- Introduced a new databaseSkillBackend to manage skill definitions and their metadata.
- Added tests for skill backend functionalities to ensure correct behavior.
- Updated various factory methods to accommodate changes in skill handling.
- Improved documentation and descriptions for better clarity.
This commit is contained in:
mlogclub
2026-04-19 09:57:34 +08:00
parent ad83d1dfda
commit 42077c1aab
21 changed files with 469 additions and 176 deletions
@@ -1,14 +1,5 @@
package runtime
import (
"context"
"encoding/json"
"strings"
"cs-agent/internal/ai/skills"
"cs-agent/internal/models"
)
func newPrepareService(catalog *toolCatalog) *prepareService {
return &prepareService{catalog: catalog}
}
@@ -17,28 +8,6 @@ type prepareService struct {
catalog *toolCatalog
}
func (s *prepareService) selectSkill(ctx context.Context, req Request) (*models.SkillDefinition, string, string, error) {
result, err := skills.Select(ctx, skills.RuntimeContext{
AIAgent: req.AIAgent,
AIConfig: req.AIConfig,
UserMessage: strings.TrimSpace(req.UserMessage.Content),
ConversationID: req.Conversation.ID,
ManualSkillCode: strings.TrimSpace(req.ManualSkillCode),
})
if err != nil {
return nil, "", "", err
}
if result == nil || result.Plan == nil || result.Plan.Skill == nil {
traceData := marshalSkillRouteTrace(result)
reason := ""
if result != nil && result.Plan != nil {
reason = strings.TrimSpace(result.Plan.MatchReason)
}
return nil, reason, traceData, nil
}
return result.Plan.Skill, strings.TrimSpace(result.Plan.MatchReason), marshalSkillRouteTrace(result), nil
}
func (s *prepareService) prepareToolsForRun(req *Request) error {
if req == nil || req.ToolSet != nil || s.catalog == nil {
return nil
@@ -66,22 +35,3 @@ func (s *prepareService) prepareToolsForResume(req *ResumeRequest) error {
}
return nil
}
func marshalSkillRouteTrace(result *skills.ExecutionResult) string {
if result == nil || result.Plan == nil || result.Plan.RouteTrace == nil {
return ""
}
buf, err := json.Marshal(result.Plan.RouteTrace)
if err != nil {
return ""
}
return string(buf)
}
func cloneSkillDefinition(item *models.SkillDefinition) *models.SkillDefinition {
if item == nil {
return nil
}
clone := *item
return &clone
}
+8 -26
View File
@@ -27,39 +27,21 @@ func (s *Service) Run(ctx context.Context, req Request) (*Summary, error) {
return nil, nil
}
req.UserMessage.Content = utils.BuildRuntimeMessageText(req.UserMessage.MessageType, req.UserMessage.Content)
selectedSkill, skillReason, skillTrace, skillErr := s.prepare.selectSkill(ctx, req)
req.SelectedSkill = selectedSkill
req.SkillRouteReason = skillReason
req.SkillRouteTrace = skillTrace
if req.SelectedSkill != nil {
req.SelectedSkill = cloneSkillDefinition(req.SelectedSkill)
}
if err := s.prepare.prepareToolsForRun(&req); err != nil {
return nil, err
}
summary, err := s.runtime.ExecuteRun(ctx, executor.RunInput{
Conversation: req.Conversation,
UserMessage: req.UserMessage,
AIAgent: req.AIAgent,
AIConfig: req.AIConfig,
SelectedSkill: req.SelectedSkill,
SkillRouteReason: req.SkillRouteReason,
SkillRouteTrace: req.SkillRouteTrace,
CheckPointID: req.CheckPointID,
ToolSet: req.ToolSet,
Conversation: req.Conversation,
UserMessage: req.UserMessage,
AIAgent: req.AIAgent,
AIConfig: req.AIConfig,
CheckPointID: req.CheckPointID,
ToolSet: req.ToolSet,
})
if err != nil {
ret := toSummary(summary)
if ret != nil && skillErr != nil && ret.PlanReason == "" {
ret.PlanReason = "skill_failed_fallback_runtime"
}
return ret, err
return toSummary(summary), err
}
ret := toSummary(summary)
if ret != nil && skillErr != nil && ret.PlanReason == "" {
ret.PlanReason = "skill_failed_fallback_runtime"
}
return ret, nil
return toSummary(summary), nil
}
func (s *Service) Resume(ctx context.Context, req ResumeRequest) (*Summary, error) {
@@ -41,7 +41,7 @@ func (c *toolCatalog) resolveForRun(req *Request) (*registry.ToolSet, error) {
AIAgent: req.AIAgent,
AIConfig: req.AIConfig,
UserMessage: req.UserMessage,
AllowedToolCodes: c.resolveAllowedToolCodes(req.AIAgent, req.SelectedSkill),
AllowedToolCodes: c.parseAgentAllowedToolCodes(req.AIAgent),
})
}
+6 -10
View File
@@ -6,16 +6,12 @@ import (
)
type Request struct {
Conversation models.Conversation
UserMessage models.Message
AIAgent models.AIAgent
AIConfig models.AIConfig
ManualSkillCode string
SelectedSkill *models.SkillDefinition
SkillRouteReason string
SkillRouteTrace string
CheckPointID string
ToolSet *registry.ToolSet
Conversation models.Conversation
UserMessage models.Message
AIAgent models.AIAgent
AIConfig models.AIConfig
CheckPointID string
ToolSet *registry.ToolSet
}
type ResumeRequest struct {