5d7c10aeab
- Updated runtime configuration to use __CS_AI_AGENT_WIDGET_CONFIG__ instead of __CS_AGENT_WIDGET_CONFIG__. - Changed message types in support host bridge from "cs-agent" to "cs-ai-agent". - Minified SDK script updated to reflect new AI agent naming conventions. - Adjusted scrollbar styles in main.scss to use .cs-ai-agent-scrollbar instead of .cs-agent-scrollbar.
225 lines
8.6 KiB
Go
225 lines
8.6 KiB
Go
package executor
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"cs-ai-agent/internal/ai/runtime/internal/impl/callbacks"
|
|
"cs-ai-agent/internal/ai/runtime/internal/impl/factory"
|
|
|
|
"github.com/cloudwego/eino/adk"
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
type Service struct {
|
|
agentFactory *factory.AgentFactory
|
|
runnerFactory *factory.RunnerFactory
|
|
answerabilityGate *KnowledgeAnswerabilityGate
|
|
}
|
|
|
|
func NewService() *Service {
|
|
return &Service{
|
|
agentFactory: factory.NewAgentFactory(),
|
|
runnerFactory: factory.NewRunnerFactory(),
|
|
answerabilityGate: NewKnowledgeAnswerabilityGate(),
|
|
}
|
|
}
|
|
|
|
func (s *Service) ExecuteRun(ctx context.Context, req RunInput) (*RunResult, error) {
|
|
summary := &RunResult{
|
|
RunID: uuid.NewString(),
|
|
Status: "started",
|
|
ToolCodes: make([]string, 0),
|
|
InvokedToolCodes: make([]string, 0),
|
|
}
|
|
collector := callbacks.NewRuntimeTraceCollector()
|
|
collector.Data.RunID = summary.RunID
|
|
summary.ModelName = req.AIConfig.ModelName
|
|
collector.Data.Model.Provider = string(req.AIConfig.Provider)
|
|
collector.Data.Model.Name = req.AIConfig.ModelName
|
|
|
|
checkPointID := resolveCheckPointID(req.CheckPointID, summary.RunID)
|
|
summary.CheckPointID = checkPointID
|
|
messages := buildRunMessages(ctx, req, summary, collector, s.answerabilityGate)
|
|
if strings.TrimSpace(summary.ReplyText) != "" {
|
|
summary.Status = "completed"
|
|
summary.ModelName = req.AIConfig.ModelName
|
|
collector.Data.Status = summary.Status
|
|
collector.Data.Output.ReplyText = summary.ReplyText
|
|
collector.Data.Output.FinishReason = summary.Status
|
|
summary.TraceData = collector.Marshal()
|
|
return summary, nil
|
|
}
|
|
|
|
toolDefs, err := factory.NewToolFactory().BuildMCPTools(req.AIAgent)
|
|
if err != nil {
|
|
summary.Status = "error"
|
|
summary.ErrorMessage = err.Error()
|
|
collector.Data.Status = summary.Status
|
|
collector.Data.Error.Message = err.Error()
|
|
collector.Data.Error.Stage = "prepare"
|
|
summary.TraceData = collector.Marshal()
|
|
return summary, err
|
|
}
|
|
hasVisibleSkills := factory.HasVisibleSkills(req.AIAgent)
|
|
tooling := prepareTooling(toolDefs, nil, req.ToolSet, hasVisibleSkills)
|
|
summary.ToolCodes = append(summary.ToolCodes, tooling.toolCodes...)
|
|
collector.Data.Input.ToolCodes = append(collector.Data.Input.ToolCodes, summary.ToolCodes...)
|
|
collector.SetTooling(tooling.staticToolCodes, definitionToolCodes(tooling.definitions), len(tooling.definitions) > 0)
|
|
|
|
agent, err := s.agentFactory.BuildCustomerServiceAgent(ctx, factory.BuildCustomerServiceAgentInput{
|
|
AIAgent: req.AIAgent,
|
|
AIConfig: req.AIConfig,
|
|
InstructionToolDefinitions: tooling.definitions,
|
|
DynamicMCPToolDefinitions: tooling.definitions,
|
|
StaticTools: tooling.staticTools,
|
|
StaticToolCodes: tooling.staticToolCodeMap,
|
|
StaticToolMetadata: tooling.staticToolMetadata,
|
|
Collector: collector,
|
|
})
|
|
if err != nil {
|
|
summary.Status = "error"
|
|
summary.ErrorMessage = err.Error()
|
|
collector.Data.Status = summary.Status
|
|
collector.Data.Error.Message = err.Error()
|
|
collector.Data.Error.Stage = "prepare"
|
|
summary.TraceData = collector.Marshal()
|
|
return summary, err
|
|
}
|
|
|
|
runner := s.runnerFactory.Build(ctx, agent, false, true)
|
|
if runner == nil {
|
|
summary.Status = "error"
|
|
summary.ErrorMessage = "failed to build runner"
|
|
collector.Data.Status = summary.Status
|
|
collector.Data.Error.Message = summary.ErrorMessage
|
|
collector.Data.Error.Stage = "prepare"
|
|
summary.TraceData = collector.Marshal()
|
|
return summary, fmt.Errorf("%s", summary.ErrorMessage)
|
|
}
|
|
collector.Data.Interrupt.CheckPointID = checkPointID
|
|
consumeAgentEvents(runner.Run(ctx, messages, buildRunOptions(checkPointID)...), summary, collector, tooling.toolDefsByModelName)
|
|
summary.ModelName = req.AIConfig.ModelName
|
|
collector.Data.Status = summary.Status
|
|
collector.Data.Output.ReplyText = summary.ReplyText
|
|
collector.Data.Output.FinishReason = summary.Status
|
|
syncSkillSummaryFromCollector(summary, collector)
|
|
summary.TraceData = collector.Marshal()
|
|
return summary, nil
|
|
}
|
|
|
|
func (s *Service) ExecuteResume(ctx context.Context, req ResumeInput) (*RunResult, error) {
|
|
summary := &RunResult{
|
|
RunID: uuid.NewString(),
|
|
Status: "started",
|
|
CheckPointID: strings.TrimSpace(req.CheckPointID),
|
|
ToolCodes: make([]string, 0),
|
|
InvokedToolCodes: make([]string, 0),
|
|
Interrupts: make([]InterruptContextSummary, 0),
|
|
}
|
|
collector := callbacks.NewRuntimeTraceCollector()
|
|
collector.Data.RunID = summary.RunID
|
|
collector.Data.Interrupt.CheckPointID = summary.CheckPointID
|
|
if summary.CheckPointID == "" {
|
|
summary.Status = "error"
|
|
summary.ErrorMessage = "checkpoint id is required"
|
|
collector.Data.Status = summary.Status
|
|
collector.Data.Error.Message = summary.ErrorMessage
|
|
collector.Data.Error.Stage = "resume_prepare"
|
|
summary.TraceData = collector.Marshal()
|
|
return summary, fmt.Errorf("%s", summary.ErrorMessage)
|
|
}
|
|
toolDefs, err := factory.NewToolFactory().BuildMCPTools(req.AIAgent)
|
|
if err != nil {
|
|
summary.Status = "error"
|
|
summary.ErrorMessage = err.Error()
|
|
collector.Data.Status = summary.Status
|
|
collector.Data.Error.Message = err.Error()
|
|
collector.Data.Error.Stage = "resume_prepare"
|
|
summary.TraceData = collector.Marshal()
|
|
return summary, err
|
|
}
|
|
hasVisibleSkills := factory.HasVisibleSkills(req.AIAgent)
|
|
tooling := prepareTooling(toolDefs, nil, req.ToolSet, hasVisibleSkills)
|
|
summary.ToolCodes = append(summary.ToolCodes, tooling.toolCodes...)
|
|
collector.Data.Input.ToolCodes = append(collector.Data.Input.ToolCodes, summary.ToolCodes...)
|
|
collector.SetTooling(tooling.staticToolCodes, definitionToolCodes(tooling.definitions), len(tooling.definitions) > 0)
|
|
collector.Data.Model.Provider = string(req.AIConfig.Provider)
|
|
collector.Data.Model.Name = req.AIConfig.ModelName
|
|
|
|
agent, err := s.agentFactory.BuildCustomerServiceAgent(ctx, factory.BuildCustomerServiceAgentInput{
|
|
AIAgent: req.AIAgent,
|
|
AIConfig: req.AIConfig,
|
|
InstructionToolDefinitions: tooling.definitions,
|
|
DynamicMCPToolDefinitions: tooling.definitions,
|
|
StaticTools: tooling.staticTools,
|
|
StaticToolCodes: tooling.staticToolCodeMap,
|
|
StaticToolMetadata: tooling.staticToolMetadata,
|
|
Collector: collector,
|
|
})
|
|
if err != nil {
|
|
summary.Status = "error"
|
|
summary.ErrorMessage = err.Error()
|
|
collector.Data.Status = summary.Status
|
|
collector.Data.Error.Message = err.Error()
|
|
collector.Data.Error.Stage = "resume_prepare"
|
|
summary.TraceData = collector.Marshal()
|
|
return summary, err
|
|
}
|
|
runner := s.runnerFactory.Build(ctx, agent, false, true)
|
|
if runner == nil {
|
|
summary.Status = "error"
|
|
summary.ErrorMessage = "failed to build runner"
|
|
collector.Data.Status = summary.Status
|
|
collector.Data.Error.Message = summary.ErrorMessage
|
|
collector.Data.Error.Stage = "resume_prepare"
|
|
summary.TraceData = collector.Marshal()
|
|
return summary, fmt.Errorf("%s", summary.ErrorMessage)
|
|
}
|
|
resumeData := buildResumeDataMessage(req.ResumeData)
|
|
resumeTargets := buildResumeTargets(req.ResumeData)
|
|
var (
|
|
iter *adk.AsyncIterator[*adk.AgentEvent]
|
|
)
|
|
if len(resumeTargets) > 0 {
|
|
iter, err = runner.ResumeWithParams(ctx, summary.CheckPointID, &adk.ResumeParams{
|
|
Targets: resumeTargets,
|
|
}, buildResumeOptions(summary.CheckPointID, resumeData)...)
|
|
} else {
|
|
iter, err = runner.Resume(ctx, summary.CheckPointID, buildResumeOptions(summary.CheckPointID, resumeData)...)
|
|
}
|
|
if err != nil {
|
|
summary.Status = "error"
|
|
summary.ErrorMessage = err.Error()
|
|
collector.Data.Status = summary.Status
|
|
collector.Data.Error.Message = err.Error()
|
|
collector.Data.Error.Stage = "resume_execute"
|
|
summary.TraceData = collector.Marshal()
|
|
return summary, err
|
|
}
|
|
consumeAgentEvents(iter, summary, collector, tooling.toolDefsByModelName)
|
|
summary.ModelName = req.AIConfig.ModelName
|
|
collector.Data.Status = summary.Status
|
|
collector.Data.Output.ReplyText = summary.ReplyText
|
|
collector.Data.Output.FinishReason = summary.Status
|
|
syncSkillSummaryFromCollector(summary, collector)
|
|
summary.TraceData = collector.Marshal()
|
|
return summary, nil
|
|
}
|
|
|
|
func syncSkillSummaryFromCollector(summary *RunResult, collector *callbacks.RuntimeTraceCollector) {
|
|
if summary == nil || collector == nil {
|
|
return
|
|
}
|
|
trace := collector.Data.Skill
|
|
summary.SelectedSkillCode = strings.TrimSpace(trace.Code)
|
|
summary.SelectedSkillName = strings.TrimSpace(trace.Name)
|
|
summary.SkillRouteReason = strings.TrimSpace(trace.RouteReason)
|
|
summary.SkillRouteTrace = strings.TrimSpace(trace.RouteTrace)
|
|
summary.SkillAllowedToolCodes = append([]string(nil), trace.AllowedToolCodes...)
|
|
if len(trace.FilteredToolCodes) > 0 {
|
|
summary.ToolCodes = append([]string(nil), trace.FilteredToolCodes...)
|
|
}
|
|
}
|