feat: refactor runtime to use application runtime executor and update related types

This commit is contained in:
mlogclub
2026-04-14 12:13:33 +08:00
parent c79d508177
commit fcb2e11998
16 changed files with 90 additions and 98 deletions
+3 -2
View File
@@ -4,6 +4,7 @@ import (
"context" "context"
runtimeeino "cs-agent/internal/ai/infra/eino" runtimeeino "cs-agent/internal/ai/infra/eino"
"cs-agent/internal/ai/runtime/executor"
) )
type Service struct { type Service struct {
@@ -35,7 +36,7 @@ func (s *Service) Run(ctx context.Context, req Request) (*Summary, error) {
if err := s.prepare.prepareToolsForRun(&req); err != nil { if err := s.prepare.prepareToolsForRun(&req); err != nil {
return nil, err return nil, err
} }
summary, err := s.runtime.ExecuteRun(ctx, runtimeeino.RunInput{ summary, err := s.runtime.ExecuteRun(ctx, executor.RunInput{
Conversation: req.Conversation, Conversation: req.Conversation,
UserMessage: req.UserMessage, UserMessage: req.UserMessage,
AIAgent: req.AIAgent, AIAgent: req.AIAgent,
@@ -67,7 +68,7 @@ func (s *Service) Resume(ctx context.Context, req ResumeRequest) (*Summary, erro
if err := s.prepare.prepareToolsForResume(&req); err != nil { if err := s.prepare.prepareToolsForResume(&req); err != nil {
return nil, err return nil, err
} }
summary, err := s.runtime.ExecuteResume(ctx, runtimeeino.ResumeInput{ summary, err := s.runtime.ExecuteResume(ctx, executor.ResumeInput{
Conversation: req.Conversation, Conversation: req.Conversation,
AIAgent: req.AIAgent, AIAgent: req.AIAgent,
AIConfig: req.AIConfig, AIConfig: req.AIConfig,
@@ -1,12 +1,11 @@
package runtime package runtime
import ( import (
"cs-agent/internal/ai/runtime/executor"
"strings" "strings"
runtimeeino "cs-agent/internal/ai/infra/eino"
) )
func toSummary(summary *runtimeeino.RunResult) *Summary { func toSummary(summary *executor.RunResult) *Summary {
if summary == nil { if summary == nil {
return nil return nil
} }
+8 -8
View File
@@ -2,30 +2,30 @@ package eino
import ( import (
"context" "context"
"cs-agent/internal/ai/runtime/executor"
runtimeexecutor "cs-agent/internal/ai/runtime/executor"
) )
// TODO 这个不要了,直接使用executor不行吗?
type RuntimeExecutor struct { type RuntimeExecutor struct {
inner *runtimeexecutor.Service inner *executor.Service
} }
func NewRuntimeExecutor() *RuntimeExecutor { func NewRuntimeExecutor() *RuntimeExecutor {
return &RuntimeExecutor{ return &RuntimeExecutor{
inner: runtimeexecutor.NewService(), inner: executor.NewService(),
} }
} }
func (s *RuntimeExecutor) ExecuteRun(ctx context.Context, req RunInput) (*RunResult, error) { func (s *RuntimeExecutor) ExecuteRun(ctx context.Context, req executor.RunInput) (*executor.RunResult, error) {
if s == nil || s.inner == nil { if s == nil || s.inner == nil {
return nil, nil return nil, nil
} }
return s.inner.ExecuteRun(ctx, runtimeexecutor.RunInput(req)) return s.inner.ExecuteRun(ctx, executor.RunInput(req))
} }
func (s *RuntimeExecutor) ExecuteResume(ctx context.Context, req ResumeInput) (*RunResult, error) { func (s *RuntimeExecutor) ExecuteResume(ctx context.Context, req executor.ResumeInput) (*executor.RunResult, error) {
if s == nil || s.inner == nil { if s == nil || s.inner == nil {
return nil, nil return nil, nil
} }
return s.inner.ExecuteResume(ctx, runtimeexecutor.ResumeInput(req)) return s.inner.ExecuteResume(ctx, executor.ResumeInput(req))
} }
-8
View File
@@ -1,8 +0,0 @@
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
+6 -5
View File
@@ -4,6 +4,7 @@ import (
"context" "context"
"strings" "strings"
applicationruntime "cs-agent/internal/ai/application/runtime"
"cs-agent/internal/ai/runtime/graphs" "cs-agent/internal/ai/runtime/graphs"
"cs-agent/internal/models" "cs-agent/internal/models"
"cs-agent/internal/pkg/dto/request" "cs-agent/internal/pkg/dto/request"
@@ -40,7 +41,7 @@ func DebugRunSkill(ctx context.Context, req request.SkillDebugRunRequest) (*resp
MessageType: enums.IMMessageTypeText, MessageType: enums.IMMessageTypeText,
Content: strings.TrimSpace(req.UserMessage), Content: strings.TrimSpace(req.UserMessage),
} }
summary, err := Service.Run(ctx, Request{ summary, err := Service.Run(ctx, applicationruntime.Request{
Conversation: conversation, Conversation: conversation,
UserMessage: message, UserMessage: message,
AIAgent: aiAgent, AIAgent: aiAgent,
@@ -88,7 +89,7 @@ func DebugResumeSkill(ctx context.Context, req request.SkillDebugResumeRequest)
return nil, errorsx.InvalidParam("会话与 AI Agent 不匹配") return nil, errorsx.InvalidParam("会话与 AI Agent 不匹配")
} }
resumeText := strings.TrimSpace(req.UserMessage) resumeText := strings.TrimSpace(req.UserMessage)
summary, err := Service.Resume(ctx, ResumeRequest{ summary, err := Service.Resume(ctx, applicationruntime.ResumeRequest{
Conversation: conversation, Conversation: conversation,
AIAgent: aiAgent, AIAgent: aiAgent,
AIConfig: aiConfig, AIConfig: aiConfig,
@@ -99,7 +100,7 @@ func DebugResumeSkill(ctx context.Context, req request.SkillDebugResumeRequest)
}) })
if err != nil { if err != nil {
if isCheckpointMissingError(err) { if isCheckpointMissingError(err) {
summary = &Summary{ summary = &applicationruntime.Summary{
Status: "expired", Status: "expired",
ReplyText: graphs.ConfirmationExpiredReply, ReplyText: graphs.ConfirmationExpiredReply,
} }
@@ -122,7 +123,7 @@ func DebugResumeSkill(ctx context.Context, req request.SkillDebugResumeRequest)
return buildSkillDebugResumeResponse(req, summary, conversationID), nil return buildSkillDebugResumeResponse(req, summary, conversationID), nil
} }
func buildSkillDebugRunResponse(req request.SkillDebugRunRequest, summary *Summary, skill *models.SkillDefinition) *response.SkillDebugRunResponse { func buildSkillDebugRunResponse(req request.SkillDebugRunRequest, summary *applicationruntime.Summary, skill *models.SkillDefinition) *response.SkillDebugRunResponse {
resp := &response.SkillDebugRunResponse{ resp := &response.SkillDebugRunResponse{
ConversationID: req.ConversationID, ConversationID: req.ConversationID,
AIAgentID: req.AIAgentID, AIAgentID: req.AIAgentID,
@@ -154,7 +155,7 @@ func buildSkillDebugRunResponse(req request.SkillDebugRunRequest, summary *Summa
return resp return resp
} }
func buildSkillDebugResumeResponse(req request.SkillDebugResumeRequest, summary *Summary, conversationID int64) *response.SkillDebugRunResponse { func buildSkillDebugResumeResponse(req request.SkillDebugResumeRequest, summary *applicationruntime.Summary, conversationID int64) *response.SkillDebugRunResponse {
resp := &response.SkillDebugRunResponse{ resp := &response.SkillDebugRunResponse{
ConversationID: conversationID, ConversationID: conversationID,
AIAgentID: req.AIAgentID, AIAgentID: req.AIAgentID,
@@ -7,29 +7,27 @@ import (
"strings" "strings"
"cs-agent/internal/ai/mcps" "cs-agent/internal/ai/mcps"
runtimetooling "cs-agent/internal/ai/runtime/tooling" "cs-agent/internal/ai/runtime/tooling"
einojsonschema "github.com/eino-contrib/jsonschema" "github.com/eino-contrib/jsonschema"
einotool "github.com/cloudwego/eino/components/tool" "github.com/cloudwego/eino/components/tool"
"github.com/cloudwego/eino/schema" "github.com/cloudwego/eino/schema"
) )
type MCPToolDefinition = runtimetooling.MCPToolDefinition
type MCPTool struct { type MCPTool struct {
definition MCPToolDefinition definition tooling.MCPToolDefinition
info *schema.ToolInfo info *schema.ToolInfo
} }
func NewMCPTool(definition MCPToolDefinition, metadata *mcps.ToolInfo) *MCPTool { func NewMCPTool(definition tooling.MCPToolDefinition, metadata *mcps.ToolInfo) *MCPTool {
return &MCPTool{ return &MCPTool{
definition: definition, definition: definition,
info: buildToolInfo(definition, metadata), info: buildToolInfo(definition, metadata),
} }
} }
var _ einotool.InvokableTool = (*MCPTool)(nil) var _ tool.InvokableTool = (*MCPTool)(nil)
func (t *MCPTool) Info(ctx context.Context) (*schema.ToolInfo, error) { func (t *MCPTool) Info(ctx context.Context) (*schema.ToolInfo, error) {
if t == nil || t.info == nil { if t == nil || t.info == nil {
@@ -38,7 +36,7 @@ func (t *MCPTool) Info(ctx context.Context) (*schema.ToolInfo, error) {
return t.info, nil return t.info, nil
} }
func (t *MCPTool) InvokableRun(ctx context.Context, argumentsInJSON string, opts ...einotool.Option) (string, error) { func (t *MCPTool) InvokableRun(ctx context.Context, argumentsInJSON string, opts ...tool.Option) (string, error) {
if t == nil { if t == nil {
return "", fmt.Errorf("mcp tool is nil") return "", fmt.Errorf("mcp tool is nil")
} }
@@ -54,7 +52,7 @@ func (t *MCPTool) InvokableRun(ctx context.Context, argumentsInJSON string, opts
return BuildReducedToolResultSummary(result), nil return BuildReducedToolResultSummary(result), nil
} }
func buildToolInfo(definition MCPToolDefinition, metadata *mcps.ToolInfo) *schema.ToolInfo { func buildToolInfo(definition tooling.MCPToolDefinition, metadata *mcps.ToolInfo) *schema.ToolInfo {
desc := strings.TrimSpace(definition.Description) desc := strings.TrimSpace(definition.Description)
if desc == "" && metadata != nil { if desc == "" && metadata != nil {
desc = strings.TrimSpace(metadata.Description) desc = strings.TrimSpace(metadata.Description)
@@ -72,7 +70,7 @@ func buildToolInfo(definition MCPToolDefinition, metadata *mcps.ToolInfo) *schem
desc = "Call MCP tool " + strings.TrimSpace(definition.ToolCode) desc = "Call MCP tool " + strings.TrimSpace(definition.ToolCode)
} }
info := &schema.ToolInfo{ info := &schema.ToolInfo{
Name: runtimetooling.BuildModelToolName(definition), Name: tooling.BuildModelToolName(definition),
Desc: desc, Desc: desc,
Extra: map[string]any{ Extra: map[string]any{
"toolCode": definition.ToolCode, "toolCode": definition.ToolCode,
@@ -86,7 +84,7 @@ func buildToolInfo(definition MCPToolDefinition, metadata *mcps.ToolInfo) *schem
return info return info
} }
func buildParamsSchema(metadata *mcps.ToolInfo) *einojsonschema.Schema { func buildParamsSchema(metadata *mcps.ToolInfo) *jsonschema.Schema {
if metadata == nil || metadata.InputSchema == nil { if metadata == nil || metadata.InputSchema == nil {
return genericObjectSchema() return genericObjectSchema()
} }
@@ -94,18 +92,18 @@ func buildParamsSchema(metadata *mcps.ToolInfo) *einojsonschema.Schema {
if err != nil || len(raw) == 0 { if err != nil || len(raw) == 0 {
return genericObjectSchema() return genericObjectSchema()
} }
js := &einojsonschema.Schema{} js := &jsonschema.Schema{}
if err := json.Unmarshal(raw, js); err != nil { if err := json.Unmarshal(raw, js); err != nil {
return genericObjectSchema() return genericObjectSchema()
} }
return js return js
} }
func genericObjectSchema() *einojsonschema.Schema { func genericObjectSchema() *jsonschema.Schema {
return &einojsonschema.Schema{ return &jsonschema.Schema{
Version: einojsonschema.Version, Version: jsonschema.Version,
Type: "object", Type: "object",
AdditionalProperties: &einojsonschema.Schema{}, AdditionalProperties: &jsonschema.Schema{},
} }
} }
+7 -6
View File
@@ -4,11 +4,12 @@ import (
"strings" "strings"
"testing" "testing"
applicationruntime "cs-agent/internal/ai/application/runtime"
"cs-agent/internal/pkg/toolx" "cs-agent/internal/pkg/toolx"
) )
func TestSummaryPrimaryToolCodePrefersToolSearchTarget(t *testing.T) { func TestSummaryPrimaryToolCodePrefersToolSearchTarget(t *testing.T) {
summary := &Summary{ summary := &applicationruntime.Summary{
InvokedToolCodes: []string{toolx.BuiltinToolSearch.Code}, InvokedToolCodes: []string{toolx.BuiltinToolSearch.Code},
TraceData: `{ TraceData: `{
"toolSearch": { "toolSearch": {
@@ -25,11 +26,11 @@ func TestSummaryPrimaryToolCodePrefersToolSearchTarget(t *testing.T) {
} }
func TestToRunLogFinalAction(t *testing.T) { func TestToRunLogFinalAction(t *testing.T) {
if got := toRunLogFinalAction(&Summary{PlannedSkillCode: "refund", ReplyText: "ok"}); got != "skill" { if got := toRunLogFinalAction(&applicationruntime.Summary{PlannedSkillCode: "refund", ReplyText: "ok"}); got != "skill" {
t.Fatalf("expected skill final action, got %q", got) t.Fatalf("expected skill final action, got %q", got)
} }
graphSummary := &Summary{ graphSummary := &applicationruntime.Summary{
ReplyText: "ok", ReplyText: "ok",
TraceData: `{ TraceData: `{
"graphTools": { "graphTools": {
@@ -43,7 +44,7 @@ func TestToRunLogFinalAction(t *testing.T) {
t.Fatalf("expected graph final action, got %q", got) t.Fatalf("expected graph final action, got %q", got)
} }
if got := toRunLogFinalAction(&Summary{Status: "fallback"}); got != "fallback" { if got := toRunLogFinalAction(&applicationruntime.Summary{Status: "fallback"}); got != "fallback" {
t.Fatalf("expected fallback final action, got %q", got) t.Fatalf("expected fallback final action, got %q", got)
} }
} }
@@ -66,7 +67,7 @@ func TestExtractInterruptMessageAndCheckpointError(t *testing.T) {
} }
func TestGraphPlanReason(t *testing.T) { func TestGraphPlanReason(t *testing.T) {
summary := &Summary{ summary := &applicationruntime.Summary{
TraceData: `{ TraceData: `{
"graphTools": { "graphTools": {
"items": [ "items": [
@@ -86,7 +87,7 @@ func TestGraphPlanReason(t *testing.T) {
} }
func TestExtractHandoffReason(t *testing.T) { func TestExtractHandoffReason(t *testing.T) {
summary := &Summary{ summary := &applicationruntime.Summary{
TraceData: `{ TraceData: `{
"graphTools": { "graphTools": {
"items": [ "items": [
@@ -5,6 +5,7 @@ import (
"strings" "strings"
"time" "time"
applicationruntime "cs-agent/internal/ai/application/runtime"
"cs-agent/internal/models" "cs-agent/internal/models"
svc "cs-agent/internal/services" svc "cs-agent/internal/services"
) )
@@ -13,7 +14,7 @@ type interruptMessagePreview struct {
Message string `json:"message"` Message string `json:"message"`
} }
func buildConversationInterrupt(conversation models.Conversation, message models.Message, aiAgent models.AIAgent, summary *Summary) *models.ConversationInterrupt { func buildConversationInterrupt(conversation models.Conversation, message models.Message, aiAgent models.AIAgent, summary *applicationruntime.Summary) *models.ConversationInterrupt {
if summary == nil { if summary == nil {
return nil return nil
} }
@@ -36,7 +37,7 @@ func buildConversationInterrupt(conversation models.Conversation, message models
return item return item
} }
func resolveInterruptPrompt(summary *Summary) string { func resolveInterruptPrompt(summary *applicationruntime.Summary) string {
if summary == nil || len(summary.Interrupts) == 0 { if summary == nil || len(summary.Interrupts) == 0 {
return "请继续补充信息后再试。" return "请继续补充信息后再试。"
} }
@@ -61,14 +62,14 @@ func extractInterruptMessage(infoPreview string) string {
return strings.TrimSpace(payload.Message) return strings.TrimSpace(payload.Message)
} }
func firstInterruptID(summary *Summary) string { func firstInterruptID(summary *applicationruntime.Summary) string {
if summary == nil || len(summary.Interrupts) == 0 { if summary == nil || len(summary.Interrupts) == 0 {
return "" return ""
} }
return strings.TrimSpace(summary.Interrupts[0].ID) return strings.TrimSpace(summary.Interrupts[0].ID)
} }
func firstInterruptType(summary *Summary) string { func firstInterruptType(summary *applicationruntime.Summary) string {
if summary == nil || len(summary.Interrupts) == 0 { if summary == nil || len(summary.Interrupts) == 0 {
return "" return ""
} }
@@ -4,6 +4,7 @@ import (
"context" "context"
"strings" "strings"
applicationruntime "cs-agent/internal/ai/application/runtime"
"cs-agent/internal/ai/runtime/graphs" "cs-agent/internal/ai/runtime/graphs"
"cs-agent/internal/models" "cs-agent/internal/models"
svc "cs-agent/internal/services" svc "cs-agent/internal/services"
@@ -16,7 +17,7 @@ func newReplyInterruptService() *replyInterruptService {
} }
func (s *replyInterruptService) ResumePendingInterrupt(ctx context.Context, owner *aiReplyService, conversation models.Conversation, message models.Message, aiAgent models.AIAgent, func (s *replyInterruptService) ResumePendingInterrupt(ctx context.Context, owner *aiReplyService, conversation models.Conversation, message models.Message, aiAgent models.AIAgent,
pendingInterrupt *models.ConversationInterrupt, trace *aiReplyTraceData, summaryRef **Summary) error { pendingInterrupt *models.ConversationInterrupt, trace *aiReplyTraceData, summaryRef **applicationruntime.Summary) error {
if pendingInterrupt == nil || owner == nil || owner.executor == nil { if pendingInterrupt == nil || owner == nil || owner.executor == nil {
return nil return nil
} }
@@ -64,7 +65,7 @@ func (s *replyInterruptService) ResumePendingInterrupt(ctx context.Context, owne
} }
func (s *replyInterruptService) HandleInterruptedSummary(owner *aiReplyService, conversation models.Conversation, message models.Message, aiAgent models.AIAgent, func (s *replyInterruptService) HandleInterruptedSummary(owner *aiReplyService, conversation models.Conversation, message models.Message, aiAgent models.AIAgent,
summary *Summary, trace *aiReplyTraceData) error { summary *applicationruntime.Summary, trace *aiReplyTraceData) error {
if owner == nil { if owner == nil {
return nil return nil
} }
@@ -85,7 +86,7 @@ func (s *replyInterruptService) HandleInterruptedSummary(owner *aiReplyService,
} }
func (s *replyInterruptService) HandleInterruptedResume(owner *aiReplyService, conversation models.Conversation, message models.Message, aiAgent models.AIAgent, func (s *replyInterruptService) HandleInterruptedResume(owner *aiReplyService, conversation models.Conversation, message models.Message, aiAgent models.AIAgent,
pendingInterrupt *models.ConversationInterrupt, summary *Summary, trace *aiReplyTraceData) error { pendingInterrupt *models.ConversationInterrupt, summary *applicationruntime.Summary, trace *aiReplyTraceData) error {
if pendingInterrupt == nil || owner == nil { if pendingInterrupt == nil || owner == nil {
return nil return nil
} }
+16 -15
View File
@@ -6,6 +6,7 @@ import (
"strings" "strings"
"time" "time"
applicationruntime "cs-agent/internal/ai/application/runtime"
"cs-agent/internal/models" "cs-agent/internal/models"
"cs-agent/internal/pkg/toolx" "cs-agent/internal/pkg/toolx"
svc "cs-agent/internal/services" svc "cs-agent/internal/services"
@@ -18,7 +19,7 @@ func newReplyRunLogService() *replyRunLogService {
type replyRunLogService struct{} type replyRunLogService struct{}
func (s *replyRunLogService) Write(startedAt time.Time, message models.Message, conversation models.Conversation, aiAgent models.AIAgent, func (s *replyRunLogService) Write(startedAt time.Time, message models.Message, conversation models.Conversation, aiAgent models.AIAgent,
question string, runErr error, trace *aiReplyTraceData, summary *Summary) { question string, runErr error, trace *aiReplyTraceData, summary *applicationruntime.Summary) {
errorMessage := "" errorMessage := ""
if runErr != nil { if runErr != nil {
errorMessage = runErr.Error() errorMessage = runErr.Error()
@@ -73,7 +74,7 @@ func buildAIReplyTraceData(trace *aiReplyTraceData) string {
return string(data) return string(data)
} }
func buildRunLogPlan(summary *Summary) (plannedAction, plannedToolCode, planReason string) { func buildRunLogPlan(summary *applicationruntime.Summary) (plannedAction, plannedToolCode, planReason string) {
if summary == nil { if summary == nil {
return "", "", "" return "", "", ""
} }
@@ -121,7 +122,7 @@ func buildRunLogPlan(summary *Summary) (plannedAction, plannedToolCode, planReas
return "fallback", "", "runtime produced empty reply" return "fallback", "", "runtime produced empty reply"
} }
func toRunLogFinalAction(summary *Summary) string { func toRunLogFinalAction(summary *applicationruntime.Summary) string {
if summary == nil { if summary == nil {
return "" return ""
} }
@@ -147,28 +148,28 @@ func toRunLogFinalAction(summary *Summary) string {
} }
} }
func buildRunLogReplyText(summary *Summary) string { func buildRunLogReplyText(summary *applicationruntime.Summary) string {
if summary == nil { if summary == nil {
return "" return ""
} }
return strings.TrimSpace(summary.ReplyText) return strings.TrimSpace(summary.ReplyText)
} }
func summaryPlannedSkillCode(summary *Summary) string { func summaryPlannedSkillCode(summary *applicationruntime.Summary) string {
if summary == nil { if summary == nil {
return "" return ""
} }
return strings.TrimSpace(summary.PlannedSkillCode) return strings.TrimSpace(summary.PlannedSkillCode)
} }
func summaryPlannedSkillName(summary *Summary) string { func summaryPlannedSkillName(summary *applicationruntime.Summary) string {
if summary == nil { if summary == nil {
return "" return ""
} }
return strings.TrimSpace(summary.PlannedSkillName) return strings.TrimSpace(summary.PlannedSkillName)
} }
func summarySkillRouteTrace(summary *Summary) string { func summarySkillRouteTrace(summary *applicationruntime.Summary) string {
if summary == nil { if summary == nil {
return "" return ""
} }
@@ -182,14 +183,14 @@ func runLogResumeSource(trace *aiReplyTraceData) string {
return strings.TrimSpace(trace.ResumeSource) return strings.TrimSpace(trace.ResumeSource)
} }
func runLogFinalStatus(summary *Summary) string { func runLogFinalStatus(summary *applicationruntime.Summary) string {
if summary == nil { if summary == nil {
return "" return ""
} }
return strings.TrimSpace(summary.Status) return strings.TrimSpace(summary.Status)
} }
func summaryPrimaryToolCode(summary *Summary) string { func summaryPrimaryToolCode(summary *applicationruntime.Summary) string {
if summary == nil { if summary == nil {
return "" return ""
} }
@@ -203,7 +204,7 @@ func summaryPrimaryToolCode(summary *Summary) string {
return toolCode return toolCode
} }
func extractToolSearchTrace(summary *Summary) string { func extractToolSearchTrace(summary *applicationruntime.Summary) string {
if summary == nil { if summary == nil {
return "" return ""
} }
@@ -218,7 +219,7 @@ func extractToolSearchTrace(summary *Summary) string {
return string(buf) return string(buf)
} }
func extractGraphToolTrace(summary *Summary) string { func extractGraphToolTrace(summary *applicationruntime.Summary) string {
if summary == nil { if summary == nil {
return "" return ""
} }
@@ -233,7 +234,7 @@ func extractGraphToolTrace(summary *Summary) string {
return string(buf) return string(buf)
} }
func firstToolSearchTargetToolCode(summary *Summary) string { func firstToolSearchTargetToolCode(summary *applicationruntime.Summary) string {
trace := parseRuntimeTraceData(summary.TraceData) trace := parseRuntimeTraceData(summary.TraceData)
for _, item := range trace.ToolSearch.Items { for _, item := range trace.ToolSearch.Items {
toolCode := strings.TrimSpace(item.TargetToolCode) toolCode := strings.TrimSpace(item.TargetToolCode)
@@ -250,7 +251,7 @@ func firstToolSearchTargetToolCode(summary *Summary) string {
return "" return ""
} }
func firstGraphToolCode(summary *Summary) string { func firstGraphToolCode(summary *applicationruntime.Summary) string {
trace := parseRuntimeTraceData(summary.TraceData) trace := parseRuntimeTraceData(summary.TraceData)
for _, item := range trace.GraphTools.Items { for _, item := range trace.GraphTools.Items {
toolCode := strings.TrimSpace(item.ToolCode) toolCode := strings.TrimSpace(item.ToolCode)
@@ -261,7 +262,7 @@ func firstGraphToolCode(summary *Summary) string {
return "" return ""
} }
func extractHandoffReason(summary *Summary) string { func extractHandoffReason(summary *applicationruntime.Summary) string {
trace := parseRuntimeTraceData(summary.TraceData) trace := parseRuntimeTraceData(summary.TraceData)
for _, item := range trace.GraphTools.Items { for _, item := range trace.GraphTools.Items {
if strings.TrimSpace(item.ToolCode) != toolx.GraphHandoffConversation.Code { if strings.TrimSpace(item.ToolCode) != toolx.GraphHandoffConversation.Code {
@@ -279,7 +280,7 @@ func extractHandoffReason(summary *Summary) string {
return "" return ""
} }
func graphPlanReason(summary *Summary) string { func graphPlanReason(summary *applicationruntime.Summary) string {
trace := parseRuntimeTraceData(summary.TraceData) trace := parseRuntimeTraceData(summary.TraceData)
for _, item := range trace.GraphTools.Items { for _, item := range trace.GraphTools.Items {
toolCode := strings.TrimSpace(item.ToolCode) toolCode := strings.TrimSpace(item.ToolCode)
+2 -1
View File
@@ -3,6 +3,7 @@ package runtime
import ( import (
"strings" "strings"
applicationruntime "cs-agent/internal/ai/application/runtime"
svc "cs-agent/internal/services" svc "cs-agent/internal/services"
) )
@@ -30,7 +31,7 @@ type aiReplyService struct {
runlog *replyRunLogService runlog *replyRunLogService
} }
func firstInvokedToolCode(summary *Summary) string { func firstInvokedToolCode(summary *applicationruntime.Summary) string {
if summary == nil { if summary == nil {
return "" return ""
} }
+8 -6
View File
@@ -7,6 +7,8 @@ import (
"cs-agent/internal/models" "cs-agent/internal/models"
"cs-agent/internal/pkg/enums" "cs-agent/internal/pkg/enums"
"cs-agent/internal/pkg/toolx" "cs-agent/internal/pkg/toolx"
applicationruntime "cs-agent/internal/ai/application/runtime"
) )
func TestReplyEligibilityCanReply(t *testing.T) { func TestReplyEligibilityCanReply(t *testing.T) {
@@ -69,7 +71,7 @@ func TestResolveReplyTimeout(t *testing.T) {
} }
func TestBuildRunLogPlan(t *testing.T) { func TestBuildRunLogPlan(t *testing.T) {
summary := &Summary{ summary := &applicationruntime.Summary{
PlannedSkillCode: "faq_router", PlannedSkillCode: "faq_router",
PlanReason: "manual", PlanReason: "manual",
} }
@@ -78,7 +80,7 @@ func TestBuildRunLogPlan(t *testing.T) {
t.Fatalf("unexpected skill plan result: action=%q toolCode=%q reason=%q", action, toolCode, reason) t.Fatalf("unexpected skill plan result: action=%q toolCode=%q reason=%q", action, toolCode, reason)
} }
summary = &Summary{ summary = &applicationruntime.Summary{
Interrupted: true, Interrupted: true,
TraceData: `{ TraceData: `{
"graphTools": { "graphTools": {
@@ -97,7 +99,7 @@ func TestBuildRunLogPlan(t *testing.T) {
t.Fatalf("unexpected graph interrupt result: action=%q toolCode=%q reason=%q", action, toolCode, reason) t.Fatalf("unexpected graph interrupt result: action=%q toolCode=%q reason=%q", action, toolCode, reason)
} }
summary = &Summary{ summary = &applicationruntime.Summary{
InvokedToolCodes: []string{toolx.BuiltinToolSearch.Code}, InvokedToolCodes: []string{toolx.BuiltinToolSearch.Code},
TraceData: `{ TraceData: `{
"toolSearch": { "toolSearch": {
@@ -114,7 +116,7 @@ func TestBuildRunLogPlan(t *testing.T) {
t.Fatalf("unexpected dynamic tool result: action=%q toolCode=%q reason=%q", action, toolCode, reason) t.Fatalf("unexpected dynamic tool result: action=%q toolCode=%q reason=%q", action, toolCode, reason)
} }
summary = &Summary{ReplyText: "done"} summary = &applicationruntime.Summary{ReplyText: "done"}
action, toolCode, reason = buildRunLogPlan(summary) action, toolCode, reason = buildRunLogPlan(summary)
if action != "reply" || toolCode != "" || reason != "agent replied directly" { if action != "reply" || toolCode != "" || reason != "agent replied directly" {
t.Fatalf("unexpected reply result: action=%q toolCode=%q reason=%q", action, toolCode, reason) t.Fatalf("unexpected reply result: action=%q toolCode=%q reason=%q", action, toolCode, reason)
@@ -122,8 +124,8 @@ func TestBuildRunLogPlan(t *testing.T) {
} }
func TestResolveInterruptPrompt(t *testing.T) { func TestResolveInterruptPrompt(t *testing.T) {
summary := &Summary{ summary := &applicationruntime.Summary{
Interrupts: []InterruptContextSummary{ Interrupts: []applicationruntime.InterruptContextSummary{
{ {
ID: "interrupt-1", ID: "interrupt-1",
Type: "question", Type: "question",
+4 -3
View File
@@ -6,6 +6,7 @@ import (
"strings" "strings"
"time" "time"
applicationruntime "cs-agent/internal/ai/application/runtime"
"cs-agent/internal/models" "cs-agent/internal/models"
"cs-agent/internal/pkg/enums" "cs-agent/internal/pkg/enums"
svc "cs-agent/internal/services" svc "cs-agent/internal/services"
@@ -44,7 +45,7 @@ func (s *aiReplyService) TriggerReplyAsync(conversation models.Conversation, mes
func (s *aiReplyService) TriggerReply(ctx context.Context, conversation models.Conversation, message models.Message, aiAgent models.AIAgent) (retErr error) { func (s *aiReplyService) TriggerReply(ctx context.Context, conversation models.Conversation, message models.Message, aiAgent models.AIAgent) (retErr error) {
startedAt := time.Now() startedAt := time.Now()
trace := &aiReplyTraceData{Status: "started"} trace := &aiReplyTraceData{Status: "started"}
var summary *Summary var summary *applicationruntime.Summary
if err := ctx.Err(); err != nil { if err := ctx.Err(); err != nil {
return err return err
} }
@@ -61,7 +62,7 @@ func (s *aiReplyService) TriggerReply(ctx context.Context, conversation models.C
} }
func (s *aiReplyService) resumePendingInterrupt(ctx context.Context, conversation models.Conversation, message models.Message, aiAgent models.AIAgent, func (s *aiReplyService) resumePendingInterrupt(ctx context.Context, conversation models.Conversation, message models.Message, aiAgent models.AIAgent,
pendingInterrupt *models.ConversationInterrupt, trace *aiReplyTraceData, summaryRef **Summary) error { pendingInterrupt *models.ConversationInterrupt, trace *aiReplyTraceData, summaryRef **applicationruntime.Summary) error {
if s == nil || s.interrupts == nil { if s == nil || s.interrupts == nil {
return nil return nil
} }
@@ -69,7 +70,7 @@ func (s *aiReplyService) resumePendingInterrupt(ctx context.Context, conversatio
} }
func (s *aiReplyService) executeReply(ctx context.Context, conversation models.Conversation, message models.Message, aiAgent models.AIAgent, func (s *aiReplyService) executeReply(ctx context.Context, conversation models.Conversation, message models.Message, aiAgent models.AIAgent,
trace *aiReplyTraceData, summaryRef **Summary) error { trace *aiReplyTraceData, summaryRef **applicationruntime.Summary) error {
if s == nil || s.executor == nil { if s == nil || s.executor == nil {
return nil return nil
} }
@@ -7,6 +7,7 @@ import (
"strings" "strings"
"time" "time"
applicationruntime "cs-agent/internal/ai/application/runtime"
"cs-agent/internal/ai/runtime/graphs" "cs-agent/internal/ai/runtime/graphs"
"cs-agent/internal/models" "cs-agent/internal/models"
svc "cs-agent/internal/services" svc "cs-agent/internal/services"
@@ -18,13 +19,13 @@ func newRuntimeReplyExecutor() *runtimeReplyExecutor {
return &runtimeReplyExecutor{} return &runtimeReplyExecutor{}
} }
func (e *runtimeReplyExecutor) Run(ctx context.Context, conversation models.Conversation, message models.Message, aiAgent models.AIAgent, trace *aiReplyTraceData) (*Summary, error) { func (e *runtimeReplyExecutor) Run(ctx context.Context, conversation models.Conversation, message models.Message, aiAgent models.AIAgent, trace *aiReplyTraceData) (*applicationruntime.Summary, error) {
aiConfig := svc.AIConfigService.Get(aiAgent.AIConfigID) aiConfig := svc.AIConfigService.Get(aiAgent.AIConfigID)
if aiConfig == nil { if aiConfig == nil {
return nil, fmt.Errorf("ai config is nil") return nil, fmt.Errorf("ai config is nil")
} }
runtimeStartedAt := time.Now() runtimeStartedAt := time.Now()
summary, err := Service.Run(ctx, Request{ summary, err := Service.Run(ctx, applicationruntime.Request{
Conversation: &conversation, Conversation: &conversation,
UserMessage: &message, UserMessage: &message,
AIAgent: &aiAgent, AIAgent: &aiAgent,
@@ -37,7 +38,7 @@ func (e *runtimeReplyExecutor) Run(ctx context.Context, conversation models.Conv
return summary, err return summary, err
} }
func (e *runtimeReplyExecutor) ResumePendingInterrupt(ctx context.Context, conversation models.Conversation, message models.Message, aiAgent models.AIAgent, pendingInterrupt *models.ConversationInterrupt, trace *aiReplyTraceData) (*Summary, error) { func (e *runtimeReplyExecutor) ResumePendingInterrupt(ctx context.Context, conversation models.Conversation, message models.Message, aiAgent models.AIAgent, pendingInterrupt *models.ConversationInterrupt, trace *aiReplyTraceData) (*applicationruntime.Summary, error) {
if pendingInterrupt == nil { if pendingInterrupt == nil {
return nil, nil return nil, nil
} }
@@ -49,7 +50,7 @@ func (e *runtimeReplyExecutor) ResumePendingInterrupt(ctx context.Context, conve
if trace != nil { if trace != nil {
trace.ResumeSource = "pending_interrupt" trace.ResumeSource = "pending_interrupt"
} }
summary, err := Service.Resume(ctx, ResumeRequest{ summary, err := Service.Resume(ctx, applicationruntime.ResumeRequest{
Conversation: &conversation, Conversation: &conversation,
AIAgent: &aiAgent, AIAgent: &aiAgent,
AIConfig: aiConfig, AIConfig: aiConfig,
@@ -65,7 +66,7 @@ func (e *runtimeReplyExecutor) ResumePendingInterrupt(ctx context.Context, conve
return summary, err return summary, err
} }
func (e *runtimeReplyExecutor) fillTraceFromSummary(trace *aiReplyTraceData, summary *Summary, runErr error) { func (e *runtimeReplyExecutor) fillTraceFromSummary(trace *aiReplyTraceData, summary *applicationruntime.Summary, runErr error) {
if trace == nil { if trace == nil {
return return
} }
@@ -84,8 +85,8 @@ func (e *runtimeReplyExecutor) fillTraceFromSummary(trace *aiReplyTraceData, sum
} }
} }
func expiredInterruptSummary() *Summary { func expiredInterruptSummary() *applicationruntime.Summary {
return &Summary{ return &applicationruntime.Summary{
Status: "expired", Status: "expired",
ReplyText: graphs.ConfirmationExpiredReply, ReplyText: graphs.ConfirmationExpiredReply,
} }
+2 -2
View File
@@ -18,14 +18,14 @@ type service struct {
app *applicationruntime.Service app *applicationruntime.Service
} }
func (s *service) Run(ctx context.Context, req Request) (*Summary, error) { func (s *service) Run(ctx context.Context, req applicationruntime.Request) (*applicationruntime.Summary, error) {
if s == nil || s.app == nil { if s == nil || s.app == nil {
return nil, nil return nil, nil
} }
return s.app.Run(ctx, req) return s.app.Run(ctx, req)
} }
func (s *service) Resume(ctx context.Context, req ResumeRequest) (*Summary, error) { func (s *service) Resume(ctx context.Context, req applicationruntime.ResumeRequest) (*applicationruntime.Summary, error) {
if s == nil || s.app == nil { if s == nil || s.app == nil {
return nil, nil return nil, nil
} }
-8
View File
@@ -1,8 +0,0 @@
package runtime
import applicationruntime "cs-agent/internal/ai/application/runtime"
type Request = applicationruntime.Request
type ResumeRequest = applicationruntime.ResumeRequest
type InterruptContextSummary = applicationruntime.InterruptContextSummary
type Summary = applicationruntime.Summary