Version: 0.9.75.dev.260505
后端: 1.收口阶段 6 agent 结构迁移,将 newAgent 内核与 agentsvc 编排层迁入 services/agent - 切换 Agent 启动装配与 HTTP handler 直连 agent sv,移除旧 service agent bridge - 补齐 Agent 对 memory、task、task-class、schedule 的 RPC 适配与契约字段 - 扩展 schedule、task、task-class RPC/contract 支撑 Agent 查询、写入与 provider 切流 - 更新迁移文档、README 与相关注释,明确 agent 当前切流点和剩余 memory 迁移面
This commit is contained in:
129
backend/services/agent/conv/schedule_preview.go
Normal file
129
backend/services/agent/conv/schedule_preview.go
Normal file
@@ -0,0 +1,129 @@
|
||||
package agentconv
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/LoveLosita/smartflow/backend/model"
|
||||
schedule "github.com/LoveLosita/smartflow/backend/services/agent/tools/schedule"
|
||||
)
|
||||
|
||||
// ScheduleStateToPreview 将 agent 的 ScheduleState 转换为前端预览缓存格式。
|
||||
//
|
||||
// 职责边界:
|
||||
// 1. 只做数据格式转换,不做业务逻辑;
|
||||
// 2. 将每个 ScheduleTask 的每个 TaskSlot 转为一条 HybridScheduleEntry;
|
||||
// 3. Day → (Week, DayOfWeek) 通过 ScheduleState.DayToWeekDay 转换;
|
||||
// 4. 转换失败的 slot(day_index 无效)静默跳过。
|
||||
func ScheduleStateToPreview(
|
||||
state *schedule.ScheduleState,
|
||||
userID int,
|
||||
conversationID string,
|
||||
taskClassIDs []int,
|
||||
summary string,
|
||||
) *model.SchedulePlanPreviewCache {
|
||||
if state == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
entries := make([]model.HybridScheduleEntry, 0, len(state.Tasks))
|
||||
for i := range state.Tasks {
|
||||
t := &state.Tasks[i]
|
||||
// 待安排且无位置的任务不生成 entry。
|
||||
if schedule.IsPendingTask(*t) {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, slot := range t.Slots {
|
||||
week, dayOfWeek, ok := state.DayToWeekDay(slot.Day)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
entry := model.HybridScheduleEntry{
|
||||
Week: week,
|
||||
DayOfWeek: dayOfWeek,
|
||||
SectionFrom: slot.SlotStart,
|
||||
SectionTo: slot.SlotEnd,
|
||||
Name: t.Name,
|
||||
}
|
||||
|
||||
// Type 映射。
|
||||
if t.Source == "event" {
|
||||
if t.EventType != "" {
|
||||
entry.Type = t.EventType
|
||||
} else {
|
||||
entry.Type = "course"
|
||||
}
|
||||
} else {
|
||||
entry.Type = "task"
|
||||
}
|
||||
|
||||
// Status 映射:existing 不变,suggested / 兼容建议态统一输出为 suggested。
|
||||
if shouldMarkSuggestedInPreview(*t) {
|
||||
entry.Status = "suggested"
|
||||
} else {
|
||||
entry.Status = "existing"
|
||||
}
|
||||
|
||||
// ID 映射。
|
||||
if t.Source == "event" {
|
||||
entry.EventID = t.SourceID
|
||||
} else {
|
||||
entry.TaskItemID = t.SourceID
|
||||
entry.TaskClassID = t.TaskClassID
|
||||
// 嵌入任务:将宿主课程的 source_id(即 event_id)桥接到 EventID,
|
||||
// 供前端作为 embed_course_event_id 传递给 BatchApplyPlans 做冲突豁免。
|
||||
if t.EmbedHost != nil {
|
||||
if host := state.TaskByStateID(*t.EmbedHost); host != nil {
|
||||
entry.EventID = host.SourceID
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 嵌入与阻塞语义。
|
||||
entry.CanBeEmbedded = t.CanEmbed
|
||||
if t.Source == "event" && t.CanEmbed && t.EmbeddedBy == nil {
|
||||
// 可嵌入且当前无嵌入任务 → 不阻塞 suggested 占位。
|
||||
entry.BlockForSuggested = false
|
||||
} else {
|
||||
entry.BlockForSuggested = true
|
||||
}
|
||||
|
||||
entries = append(entries, entry)
|
||||
}
|
||||
}
|
||||
|
||||
// 生成摘要(若调用方未提供)。
|
||||
if summary == "" {
|
||||
existingCount := 0
|
||||
suggestedCount := 0
|
||||
for _, e := range entries {
|
||||
if e.Status == "existing" {
|
||||
existingCount++
|
||||
} else {
|
||||
suggestedCount++
|
||||
}
|
||||
}
|
||||
summary = fmt.Sprintf("共 %d 个日程条目,其中已确定 %d 个,新安排 %d 个。", len(entries), existingCount, suggestedCount)
|
||||
}
|
||||
|
||||
return &model.SchedulePlanPreviewCache{
|
||||
UserID: userID,
|
||||
ConversationID: conversationID,
|
||||
Summary: summary,
|
||||
HybridEntries: entries,
|
||||
TaskClassIDs: taskClassIDs,
|
||||
GeneratedAt: time.Now(),
|
||||
}
|
||||
}
|
||||
|
||||
// shouldMarkSuggestedInPreview 判断某条 ScheduleTask 在预览层是否应标记为 suggested。
|
||||
//
|
||||
// 规则说明:
|
||||
// 1. 新语义下,显式 suggested 直接输出为建议态;
|
||||
// 2. 兼容旧快照:pending+Slots、existing+Duration>0 的 task_item 也继续按 suggested 输出;
|
||||
// 3. 这样前端预览口径可以在迁移期保持稳定,不会因为状态枚举切换而抖动。
|
||||
func shouldMarkSuggestedInPreview(t schedule.ScheduleTask) bool {
|
||||
return schedule.IsSuggestedTask(t)
|
||||
}
|
||||
Reference in New Issue
Block a user