Refactor runtime executor integration and introduce eino package

- Replaced the existing runtime executor with a new eino package for better modularity.
- Updated Service struct to use the new RuntimeExecutor from eino.
- Adjusted Run and Resume methods to accommodate changes in input types and execution logic.
- Introduced new types in the eino package to align with the previous executor's functionality.
- Refactored tooling preparation logic to streamline tool definitions and improve clarity.
- Added new context builders and event consumers to enhance runtime event handling.
- Removed legacy executor code and ensured all references are updated to the new eino package.
This commit is contained in:
mlogclub
2026-04-14 09:33:49 +08:00
parent f5bbb0aaf2
commit 164121836d
15 changed files with 335 additions and 297 deletions
+5 -5
View File
@@ -3,11 +3,11 @@ package runtime
import (
"context"
runtimeexecutor "cs-agent/internal/ai/runtime/executor"
runtimeeino "cs-agent/internal/ai/infra/eino"
)
type Service struct {
runtime *runtimeexecutor.Service
runtime *runtimeeino.RuntimeExecutor
catalog *toolCatalog
prepare *prepareService
}
@@ -15,7 +15,7 @@ type Service struct {
func NewService() *Service {
catalog := newToolCatalog()
return &Service{
runtime: runtimeexecutor.NewService(),
runtime: runtimeeino.NewRuntimeExecutor(),
catalog: catalog,
prepare: newPrepareService(catalog),
}
@@ -35,7 +35,7 @@ func (s *Service) Run(ctx context.Context, req Request) (*Summary, error) {
if err := s.prepare.prepareToolsForRun(&req); err != nil {
return nil, err
}
summary, err := s.runtime.ExecuteRun(ctx, runtimeexecutor.RunInput{
summary, err := s.runtime.ExecuteRun(ctx, runtimeeino.RunInput{
Conversation: req.Conversation,
UserMessage: req.UserMessage,
AIAgent: req.AIAgent,
@@ -67,7 +67,7 @@ func (s *Service) Resume(ctx context.Context, req ResumeRequest) (*Summary, erro
if err := s.prepare.prepareToolsForResume(&req); err != nil {
return nil, err
}
summary, err := s.runtime.ExecuteResume(ctx, runtimeexecutor.ResumeInput{
summary, err := s.runtime.ExecuteResume(ctx, runtimeeino.ResumeInput{
Conversation: req.Conversation,
AIAgent: req.AIAgent,
AIConfig: req.AIConfig,
@@ -3,10 +3,10 @@ package runtime
import (
"strings"
runtimeexecutor "cs-agent/internal/ai/runtime/executor"
runtimeeino "cs-agent/internal/ai/infra/eino"
)
func toSummary(summary *runtimeexecutor.RunResult) *Summary {
func toSummary(summary *runtimeeino.RunResult) *Summary {
if summary == nil {
return nil
}
+31
View File
@@ -0,0 +1,31 @@
package eino
import (
"context"
runtimeexecutor "cs-agent/internal/ai/runtime/executor"
)
type RuntimeExecutor struct {
inner *runtimeexecutor.Service
}
func NewRuntimeExecutor() *RuntimeExecutor {
return &RuntimeExecutor{
inner: runtimeexecutor.NewService(),
}
}
func (s *RuntimeExecutor) ExecuteRun(ctx context.Context, req RunInput) (*RunResult, error) {
if s == nil || s.inner == nil {
return nil, nil
}
return s.inner.ExecuteRun(ctx, runtimeexecutor.RunInput(req))
}
func (s *RuntimeExecutor) ExecuteResume(ctx context.Context, req ResumeInput) (*RunResult, error) {
if s == nil || s.inner == nil {
return nil, nil
}
return s.inner.ExecuteResume(ctx, runtimeexecutor.ResumeInput(req))
}
+8
View File
@@ -0,0 +1,8 @@
package eino
import runtimeexecutor "cs-agent/internal/ai/runtime/executor"
type RunInput = runtimeexecutor.RunInput
type ResumeInput = runtimeexecutor.ResumeInput
type InterruptContextSummary = runtimeexecutor.InterruptContextSummary
type RunResult = runtimeexecutor.RunResult
+211 -9
View File
@@ -2,30 +2,232 @@ package executor
import (
"context"
"fmt"
"strings"
internalexecutor "cs-agent/internal/ai/runtime/internal/executor"
"cs-agent/internal/ai/runtime/internal/impl/callbacks"
"cs-agent/internal/ai/runtime/internal/impl/factory"
"github.com/google/uuid"
)
type Service struct {
inner *internalexecutor.Service
agentFactory *factory.AgentFactory
runnerFactory *factory.RunnerFactory
}
func NewService() *Service {
return &Service{
inner: internalexecutor.NewService(),
agentFactory: factory.NewAgentFactory(),
runnerFactory: factory.NewRunnerFactory(),
}
}
func (s *Service) ExecuteRun(ctx context.Context, req RunInput) (*RunResult, error) {
if s == nil || s.inner == nil {
return nil, nil
summary := &RunResult{
RunID: uuid.NewString(),
Status: "started",
ToolCodes: make([]string, 0),
InvokedToolCodes: make([]string, 0),
}
return s.inner.ExecuteRun(ctx, req)
collector := callbacks.NewRuntimeTraceCollector()
collector.Data.RunID = summary.RunID
if req.AIAgent == nil || req.Conversation == nil || req.UserMessage == nil {
summary.Status = "error"
summary.ErrorMessage = "invalid runtime request"
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)
}
if req.AIConfig == nil {
summary.Status = "error"
summary.ErrorMessage = "ai config is nil"
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)
}
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
}
tooling := prepareTooling(toolDefs, req.SelectedSkill, req.ToolSet, req.SelectedSkill != nil)
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
summary.SelectedSkillCode = ""
summary.SelectedSkillName = ""
summary.SkillRouteReason = strings.TrimSpace(req.SkillRouteReason)
summary.SkillRouteTrace = strings.TrimSpace(req.SkillRouteTrace)
if req.SelectedSkill != nil {
summary.SelectedSkillCode = strings.TrimSpace(req.SelectedSkill.Code)
summary.SelectedSkillName = strings.TrimSpace(req.SelectedSkill.Name)
summary.SkillAllowedToolCodes = parseJSONArrayList(req.SelectedSkill.ToolWhitelist)
collector.Data.Skill.Code = summary.SelectedSkillCode
collector.Data.Skill.Name = summary.SelectedSkillName
collector.Data.Skill.AllowedToolCodes = append([]string(nil), summary.SkillAllowedToolCodes...)
}
collector.Data.Skill.RouteReason = summary.SkillRouteReason
collector.Data.Skill.RouteTrace = summary.SkillRouteTrace
agent, err := s.agentFactory.BuildCustomerServiceAgent(ctx, factory.BuildCustomerServiceAgentInput{
AIAgent: req.AIAgent,
AIConfig: req.AIConfig,
SelectedSkill: req.SelectedSkill,
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
}
checkPointID := resolveCheckPointID(req.CheckPointID, summary.RunID)
summary.CheckPointID = checkPointID
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)
}
messages := buildRunMessages(ctx, req, summary, collector)
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
summary.TraceData = collector.Marshal()
return summary, nil
}
func (s *Service) ExecuteResume(ctx context.Context, req ResumeInput) (*RunResult, error) {
if s == nil || s.inner == nil {
return nil, nil
summary := &RunResult{
RunID: uuid.NewString(),
Status: "started",
CheckPointID: strings.TrimSpace(req.CheckPointID),
ToolCodes: make([]string, 0),
InvokedToolCodes: make([]string, 0),
Interrupts: make([]InterruptContextSummary, 0),
}
return s.inner.ExecuteResume(ctx, req)
collector := callbacks.NewRuntimeTraceCollector()
collector.Data.RunID = summary.RunID
collector.Data.Interrupt.CheckPointID = summary.CheckPointID
if req.AIAgent == nil {
summary.Status = "error"
summary.ErrorMessage = "ai agent is nil"
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)
}
if req.AIConfig == nil {
summary.Status = "error"
summary.ErrorMessage = "ai config is nil"
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)
}
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
}
tooling := prepareTooling(toolDefs, nil, req.ToolSet, false)
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)
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
summary.TraceData = collector.Marshal()
return summary, nil
}
+54 -6
View File
@@ -1,9 +1,57 @@
package executor
import internalexecutor "cs-agent/internal/ai/runtime/internal/executor"
import (
"cs-agent/internal/ai/runtime/registry"
"cs-agent/internal/models"
)
// TODO 为什么要定义类型别名?
type RunInput = internalexecutor.RunInput
type ResumeInput = internalexecutor.ResumeInput
type InterruptContextSummary = internalexecutor.InterruptContextSummary
type RunResult = internalexecutor.RunResult
type RunInput struct {
Conversation *models.Conversation
UserMessage *models.Message
AIAgent *models.AIAgent
AIConfig *models.AIConfig
SelectedSkill *models.SkillDefinition
SkillRouteReason string
SkillRouteTrace string
CheckPointID string
ToolSet *registry.ToolSet
}
type ResumeInput struct {
Conversation *models.Conversation
AIAgent *models.AIAgent
AIConfig *models.AIConfig
CheckPointID string
ResumeData map[string]any
ToolSet *registry.ToolSet
}
type InterruptContextSummary struct {
Type string `json:"type,omitempty"`
ID string `json:"id"`
InfoPreview string `json:"infoPreview,omitempty"`
}
type RunResult struct {
RunID string
Status string
ReplyText string
SelectedSkillCode string
SelectedSkillName string
SkillRouteReason string
SkillRouteTrace string
SkillAllowedToolCodes []string
ModelName string
PromptTokens int
CompletionTokens int
HistoryMessageCount int
RetrieverCount int
ToolCallCount int
ToolCodes []string
InvokedToolCodes []string
CheckPointID string
Interrupted bool
Interrupts []InterruptContextSummary
TraceData string
ErrorMessage string
}
@@ -3,16 +3,16 @@ package engine
import (
"context"
"cs-agent/internal/ai/runtime/internal/executor"
runtimeeino "cs-agent/internal/ai/infra/eino"
)
type Service struct {
executor *executor.Service
executor *runtimeeino.RuntimeExecutor
}
func NewService() *Service {
return &Service{
executor: executor.NewService(),
executor: runtimeeino.NewRuntimeExecutor(),
}
}
@@ -21,7 +21,7 @@ func (s *Service) Run(ctx context.Context, req Request) (*Summary, error) {
}
func (s *Service) ExecuteRun(ctx context.Context, req RunInput) (*RunResult, error) {
return s.executor.ExecuteRun(ctx, executor.RunInput(req))
return s.executor.ExecuteRun(ctx, runtimeeino.RunInput(req))
}
func (s *Service) Resume(ctx context.Context, req ResumeRequest) (*Summary, error) {
@@ -29,5 +29,5 @@ func (s *Service) Resume(ctx context.Context, req ResumeRequest) (*Summary, erro
}
func (s *Service) ExecuteResume(ctx context.Context, req ResumeInput) (*RunResult, error) {
return s.executor.ExecuteResume(ctx, executor.ResumeInput(req))
return s.executor.ExecuteResume(ctx, runtimeeino.ResumeInput(req))
}
+5 -5
View File
@@ -1,12 +1,12 @@
package engine
import "cs-agent/internal/ai/runtime/internal/executor"
import runtimeeino "cs-agent/internal/ai/infra/eino"
// TODO 这个地方为什么要定义类型别名,不能直接用吗?
type RunInput = executor.RunInput
type ResumeInput = executor.ResumeInput
type InterruptContextSummary = executor.InterruptContextSummary
type RunResult = executor.RunResult
type RunInput = runtimeeino.RunInput
type ResumeInput = runtimeeino.ResumeInput
type InterruptContextSummary = runtimeeino.InterruptContextSummary
type RunResult = runtimeeino.RunResult
type Request = RunInput
type ResumeRequest = ResumeInput
@@ -2,232 +2,30 @@ package executor
import (
"context"
"fmt"
"strings"
"cs-agent/internal/ai/runtime/internal/impl/callbacks"
"cs-agent/internal/ai/runtime/internal/impl/factory"
"github.com/google/uuid"
publicexecutor "cs-agent/internal/ai/runtime/executor"
)
type Service struct {
agentFactory *factory.AgentFactory
runnerFactory *factory.RunnerFactory
inner *publicexecutor.Service
}
func NewService() *Service {
return &Service{
agentFactory: factory.NewAgentFactory(),
runnerFactory: factory.NewRunnerFactory(),
inner: publicexecutor.NewService(),
}
}
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),
if s == nil || s.inner == nil {
return nil, nil
}
collector := callbacks.NewRuntimeTraceCollector()
collector.Data.RunID = summary.RunID
if req.AIAgent == nil || req.Conversation == nil || req.UserMessage == nil {
summary.Status = "error"
summary.ErrorMessage = "invalid runtime request"
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)
}
if req.AIConfig == nil {
summary.Status = "error"
summary.ErrorMessage = "ai config is nil"
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)
}
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
}
tooling := prepareTooling(toolDefs, req.SelectedSkill, req.ToolSet, req.SelectedSkill != nil)
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
summary.SelectedSkillCode = ""
summary.SelectedSkillName = ""
summary.SkillRouteReason = strings.TrimSpace(req.SkillRouteReason)
summary.SkillRouteTrace = strings.TrimSpace(req.SkillRouteTrace)
if req.SelectedSkill != nil {
summary.SelectedSkillCode = strings.TrimSpace(req.SelectedSkill.Code)
summary.SelectedSkillName = strings.TrimSpace(req.SelectedSkill.Name)
summary.SkillAllowedToolCodes = parseJSONArrayList(req.SelectedSkill.ToolWhitelist)
collector.Data.Skill.Code = summary.SelectedSkillCode
collector.Data.Skill.Name = summary.SelectedSkillName
collector.Data.Skill.AllowedToolCodes = append([]string(nil), summary.SkillAllowedToolCodes...)
}
collector.Data.Skill.RouteReason = summary.SkillRouteReason
collector.Data.Skill.RouteTrace = summary.SkillRouteTrace
agent, err := s.agentFactory.BuildCustomerServiceAgent(ctx, factory.BuildCustomerServiceAgentInput{
AIAgent: req.AIAgent,
AIConfig: req.AIConfig,
SelectedSkill: req.SelectedSkill,
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
}
checkPointID := resolveCheckPointID(req.CheckPointID, summary.RunID)
summary.CheckPointID = checkPointID
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)
}
messages := buildRunMessages(ctx, req, summary, collector)
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
summary.TraceData = collector.Marshal()
return summary, nil
return s.inner.ExecuteRun(ctx, publicexecutor.RunInput(req))
}
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),
if s == nil || s.inner == nil {
return nil, nil
}
collector := callbacks.NewRuntimeTraceCollector()
collector.Data.RunID = summary.RunID
collector.Data.Interrupt.CheckPointID = summary.CheckPointID
if req.AIAgent == nil {
summary.Status = "error"
summary.ErrorMessage = "ai agent is nil"
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)
}
if req.AIConfig == nil {
summary.Status = "error"
summary.ErrorMessage = "ai config is nil"
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)
}
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
}
tooling := prepareTooling(toolDefs, nil, req.ToolSet, false)
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)
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
summary.TraceData = collector.Marshal()
return summary, nil
return s.inner.ExecuteResume(ctx, publicexecutor.ResumeInput(req))
}
+5 -54
View File
@@ -1,57 +1,8 @@
package executor
import (
"cs-agent/internal/ai/runtime/registry"
"cs-agent/internal/models"
)
import publicexecutor "cs-agent/internal/ai/runtime/executor"
type RunInput struct {
Conversation *models.Conversation
UserMessage *models.Message
AIAgent *models.AIAgent
AIConfig *models.AIConfig
SelectedSkill *models.SkillDefinition
SkillRouteReason string
SkillRouteTrace string
CheckPointID string
ToolSet *registry.ToolSet
}
type ResumeInput struct {
Conversation *models.Conversation
AIAgent *models.AIAgent
AIConfig *models.AIConfig
CheckPointID string
ResumeData map[string]any
ToolSet *registry.ToolSet
}
type InterruptContextSummary struct {
Type string `json:"type,omitempty"`
ID string `json:"id"`
InfoPreview string `json:"infoPreview,omitempty"`
}
type RunResult struct {
RunID string
Status string
ReplyText string
SelectedSkillCode string
SelectedSkillName string
SkillRouteReason string
SkillRouteTrace string
SkillAllowedToolCodes []string
ModelName string
PromptTokens int
CompletionTokens int
HistoryMessageCount int
RetrieverCount int
ToolCallCount int
ToolCodes []string
InvokedToolCodes []string
CheckPointID string
Interrupted bool
Interrupts []InterruptContextSummary
TraceData string
ErrorMessage string
}
type RunInput = publicexecutor.RunInput
type ResumeInput = publicexecutor.ResumeInput
type InterruptContextSummary = publicexecutor.InterruptContextSummary
type RunResult = publicexecutor.RunResult