168 lines
4.7 KiB
Go
168 lines
4.7 KiB
Go
package app
|
|
|
|
import (
|
|
"context"
|
|
|
|
"chat-agent-system/internal/app/chatflow"
|
|
"chat-agent-system/internal/app/intentflow"
|
|
"chat-agent-system/internal/bizdev"
|
|
"chat-agent-system/internal/chat"
|
|
"chat-agent-system/internal/coordinator"
|
|
"chat-agent-system/internal/ctxmgr"
|
|
"chat-agent-system/internal/taskrun"
|
|
)
|
|
|
|
// AdaptChatMemory wraps chatflow.ChatLog as the chat-owned ChatMemory port.
|
|
func AdaptChatMemory(log chatflow.ChatLog) chat.ChatMemory {
|
|
if log == nil {
|
|
return nil
|
|
}
|
|
return chatMemoryAdapter{inner: log}
|
|
}
|
|
|
|
type chatMemoryAdapter struct {
|
|
inner chatflow.ChatLog
|
|
}
|
|
|
|
func (a chatMemoryAdapter) SearchMemory(ctx context.Context, userID int64, q chat.MemoryQuery) ([]ctxmgr.RecalledMemoryItem, error) {
|
|
return a.inner.SearchMemory(ctx, chatflow.Principal{UserID: userID, Action: chatflow.ActionAssemble}, chatflow.MemoryQuery{
|
|
Query: q.Query,
|
|
ProjectID: q.ProjectID,
|
|
SessionID: q.SessionID,
|
|
ExcludeSessionID: q.ExcludeSessionID,
|
|
TopK: q.TopK,
|
|
MinScore: q.MinScore,
|
|
})
|
|
}
|
|
|
|
// AdaptChatIntentPlans wraps intentflow.Service as the chat-owned IntentPlans port.
|
|
func AdaptChatIntentPlans(svc intentflow.Service) chat.IntentPlans {
|
|
if svc == nil {
|
|
return nil
|
|
}
|
|
return chatIntentPlansAdapter{inner: svc}
|
|
}
|
|
|
|
type chatIntentPlansAdapter struct {
|
|
inner intentflow.Service
|
|
}
|
|
|
|
func (a chatIntentPlansAdapter) HandleTurn(ctx context.Context, in chat.IntentTurnInput) (*chat.IntentTurnResult, error) {
|
|
tr, err := a.inner.HandleTurn(ctx, intentflow.TurnInput{
|
|
Principal: intentflow.Principal{
|
|
UserID: in.UserID,
|
|
Environment: in.Environment,
|
|
ProjectID: in.ProjectID,
|
|
SessionID: in.SessionID,
|
|
},
|
|
Text: in.Text,
|
|
ClientTurnID: in.ClientTurnID,
|
|
RequestDigest: in.RequestDigest,
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if tr == nil {
|
|
return &chat.IntentTurnResult{}, nil
|
|
}
|
|
return &chat.IntentTurnResult{Plan: mapIntentPlanView(tr.Plan)}, nil
|
|
}
|
|
|
|
func mapIntentPlanView(p *intentflow.PlanView) *chat.IntentPlanView {
|
|
if p == nil {
|
|
return nil
|
|
}
|
|
out := &chat.IntentPlanView{
|
|
PlanID: p.PlanID,
|
|
Revision: p.Revision,
|
|
Status: string(p.Status),
|
|
ExecutionMode: string(p.ExecutionMode),
|
|
ExpiresAt: p.ExpiresAt,
|
|
SafeSummary: p.SafeSummary,
|
|
}
|
|
if len(p.Steps) > 0 {
|
|
out.Steps = make([]chat.IntentStepView, 0, len(p.Steps))
|
|
for _, s := range p.Steps {
|
|
out.Steps = append(out.Steps, chat.IntentStepView{
|
|
StepID: s.StepID,
|
|
ActionKey: s.ActionKey,
|
|
Status: string(s.Status),
|
|
ExecutionMode: string(s.ExecutionMode),
|
|
DependsOn: append([]string(nil), s.DependsOn...),
|
|
SafeSummary: s.SafeSummary,
|
|
})
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
|
|
// AdaptChatTaskStarter wraps taskrun.Manager as the chat-owned TaskStarter port.
|
|
func AdaptChatTaskStarter(m *taskrun.Manager) chat.TaskStarter {
|
|
if m == nil {
|
|
return nil
|
|
}
|
|
return chatTaskStarter{inner: m}
|
|
}
|
|
|
|
type chatTaskStarter struct {
|
|
inner *taskrun.Manager
|
|
}
|
|
|
|
func (a chatTaskStarter) CreateAndStart(ctx context.Context, runID string, record *taskrun.RunRecord, req chat.TaskStartRequest, resumeDir string) (*taskrun.RunRecord, error) {
|
|
return a.inner.CreateAndStart(ctx, runID, record, bizdev.TaskRunRequest{
|
|
TaskKey: req.TaskKey,
|
|
ProjectName: req.ProjectName,
|
|
UserID: req.UserID,
|
|
ProjectID: req.ProjectID,
|
|
SessionID: req.SessionID,
|
|
}, bizdev.StageRunRequest{}, resumeDir)
|
|
}
|
|
|
|
func (a chatTaskStarter) BindAssistantMsgID(ctx context.Context, runID string, assistantMsgID int64) error {
|
|
return a.inner.BindAssistantMsgID(ctx, runID, assistantMsgID)
|
|
}
|
|
|
|
// BindChatSession attaches composition-root adapters onto a chat session.
|
|
// Callers that keep a mutable intentflow.Service (e.g. server test hooks) should
|
|
// prefer AdaptChat* helpers with their own fields so swaps stay visible.
|
|
func (rt *Runtime) BindChatSession(sess *chat.Session, env string) {
|
|
if rt == nil || sess == nil {
|
|
return
|
|
}
|
|
if env == "" {
|
|
env = "dev"
|
|
if rt.Cfg != nil && rt.Cfg.Env != "" {
|
|
env = rt.Cfg.Env
|
|
}
|
|
}
|
|
sess.ChatLog = AdaptChatMemory(rt.ChatLog)
|
|
sess.Actions = &chat.ActionServices{
|
|
DocGov: rt.Gov,
|
|
TaskRuns: AdaptChatTaskStarter(rt.TaskRuns),
|
|
IntentPlans: AdaptChatIntentPlans(rt.IntentPlans),
|
|
Environment: env,
|
|
}
|
|
}
|
|
|
|
type sessionRunAdapter struct {
|
|
mgr *taskrun.Manager
|
|
}
|
|
|
|
func (a sessionRunAdapter) LatestSessionRun(ctx context.Context, sessionID string) (*coordinator.SessionRunSnapshot, error) {
|
|
if a.mgr == nil {
|
|
return nil, nil
|
|
}
|
|
rec, err := a.mgr.LatestSessionRun(ctx, sessionID)
|
|
if err != nil || rec == nil {
|
|
return nil, err
|
|
}
|
|
return &coordinator.SessionRunSnapshot{
|
|
RunID: rec.RunID,
|
|
TaskKey: rec.TaskKey,
|
|
Status: rec.Status,
|
|
WorkspaceID: rec.WorkspaceID,
|
|
ErrorMessage: rec.ErrorMessage,
|
|
UpdatedAt: rec.UpdatedAt,
|
|
}, nil
|
|
}
|