Version: 0.9.15.dev.260412
后端: 1. 排程工具从 tools/ 根目录拆分为 tools/schedule 独立子包 - 12 个排程工具文件等价迁入 tools/schedule/,tools/ 根目录仅保留 registry.go 作为统一注册入口 - 所有依赖方(conv / model / node / prompt / service)import 统一切到 schedule 子包 2. Web 搜索工具链落地(tools/web 子包) - 新增 web_search(结构化检索)与 web_fetch(正文抓取)两个读工具,支持博查 API / mock 降级 - 启动流程按配置选择 provider,未识别类型自动降级为 mock,不阻断主流程 - 执行提示补齐 web 工具使用约束与返回值示例 - config.example.yaml 补齐 websearch 配置段 前端:无 仓库:无
This commit is contained in:
@@ -7,7 +7,7 @@ import (
|
||||
baseconv "github.com/LoveLosita/smartflow/backend/conv"
|
||||
"github.com/LoveLosita/smartflow/backend/dao"
|
||||
"github.com/LoveLosita/smartflow/backend/model"
|
||||
newagenttools "github.com/LoveLosita/smartflow/backend/newAgent/tools"
|
||||
schedule "github.com/LoveLosita/smartflow/backend/newAgent/tools/schedule"
|
||||
)
|
||||
|
||||
// SchedulePersistorAdapter 实现 model.SchedulePersistor 接口。
|
||||
@@ -22,7 +22,7 @@ func NewSchedulePersistorAdapter(manager *dao.RepoManager) *SchedulePersistorAda
|
||||
}
|
||||
|
||||
// PersistScheduleChanges 实现 model.SchedulePersistor 接口。
|
||||
func (a *SchedulePersistorAdapter) PersistScheduleChanges(ctx context.Context, original, modified *newagenttools.ScheduleState, userID int) error {
|
||||
func (a *SchedulePersistorAdapter) PersistScheduleChanges(ctx context.Context, original, modified *schedule.ScheduleState, userID int) error {
|
||||
return PersistScheduleChanges(ctx, a.manager, original, modified, userID)
|
||||
}
|
||||
|
||||
@@ -35,8 +35,8 @@ func (a *SchedulePersistorAdapter) PersistScheduleChanges(ctx context.Context, o
|
||||
func PersistScheduleChanges(
|
||||
ctx context.Context,
|
||||
manager *dao.RepoManager,
|
||||
original *newagenttools.ScheduleState,
|
||||
modified *newagenttools.ScheduleState,
|
||||
original *schedule.ScheduleState,
|
||||
modified *schedule.ScheduleState,
|
||||
userID int,
|
||||
) error {
|
||||
changes := DiffScheduleState(original, modified)
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/LoveLosita/smartflow/backend/model"
|
||||
newagenttools "github.com/LoveLosita/smartflow/backend/newAgent/tools"
|
||||
schedule "github.com/LoveLosita/smartflow/backend/newAgent/tools/schedule"
|
||||
)
|
||||
|
||||
// ScheduleStateToPreview 将 newAgent 的 ScheduleState 转换为前端预览缓存格式。
|
||||
@@ -16,7 +16,7 @@ import (
|
||||
// 3. Day → (Week, DayOfWeek) 通过 ScheduleState.DayToWeekDay 转换;
|
||||
// 4. 转换失败的 slot(day_index 无效)静默跳过。
|
||||
func ScheduleStateToPreview(
|
||||
state *newagenttools.ScheduleState,
|
||||
state *schedule.ScheduleState,
|
||||
userID int,
|
||||
conversationID string,
|
||||
taskClassIDs []int,
|
||||
@@ -30,7 +30,7 @@ func ScheduleStateToPreview(
|
||||
for i := range state.Tasks {
|
||||
t := &state.Tasks[i]
|
||||
// 待安排且无位置的任务不生成 entry。
|
||||
if newagenttools.IsPendingTask(*t) {
|
||||
if schedule.IsPendingTask(*t) {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -116,6 +116,6 @@ func ScheduleStateToPreview(
|
||||
// 1. 新语义下,显式 suggested 直接输出为建议态;
|
||||
// 2. 兼容旧快照:pending+Slots、existing+Duration>0 的 task_item 也继续按 suggested 输出;
|
||||
// 3. 这样前端预览口径可以在迁移期保持稳定,不会因为状态枚举切换而抖动。
|
||||
func shouldMarkSuggestedInPreview(t newagenttools.ScheduleTask) bool {
|
||||
return newagenttools.IsSuggestedTask(t)
|
||||
func shouldMarkSuggestedInPreview(t schedule.ScheduleTask) bool {
|
||||
return schedule.IsSuggestedTask(t)
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
baseconv "github.com/LoveLosita/smartflow/backend/conv"
|
||||
"github.com/LoveLosita/smartflow/backend/dao"
|
||||
"github.com/LoveLosita/smartflow/backend/model"
|
||||
newagenttools "github.com/LoveLosita/smartflow/backend/newAgent/tools"
|
||||
schedule "github.com/LoveLosita/smartflow/backend/newAgent/tools/schedule"
|
||||
)
|
||||
|
||||
// ScheduleProvider 实现 model.ScheduleStateProvider 接口。
|
||||
@@ -39,7 +39,7 @@ func NewScheduleProvider(scheduleDAO *dao.ScheduleDAO, taskClassDAO *dao.TaskCla
|
||||
// 2. task class 无日期信息时,降级到当前周 7 天(兼容普通查询场景)。
|
||||
//
|
||||
// 日程加载策略:对窗口内每周分别调用 GetUserWeeklySchedule 并合并结果。
|
||||
func (p *ScheduleProvider) LoadScheduleState(ctx context.Context, userID int) (*newagenttools.ScheduleState, error) {
|
||||
func (p *ScheduleProvider) LoadScheduleState(ctx context.Context, userID int) (*schedule.ScheduleState, error) {
|
||||
// 1. 加载用户所有任务类(含 Items 预加载)。
|
||||
taskClasses, err := p.loadCompleteTaskClasses(ctx, userID)
|
||||
if err != nil {
|
||||
@@ -59,7 +59,7 @@ func (p *ScheduleProvider) LoadScheduleStateForTaskClasses(
|
||||
ctx context.Context,
|
||||
userID int,
|
||||
taskClassIDs []int,
|
||||
) (*newagenttools.ScheduleState, error) {
|
||||
) (*schedule.ScheduleState, error) {
|
||||
if len(taskClassIDs) == 0 {
|
||||
return p.LoadScheduleState(ctx, userID)
|
||||
}
|
||||
@@ -82,7 +82,7 @@ func (p *ScheduleProvider) loadScheduleStateWithTaskClasses(
|
||||
ctx context.Context,
|
||||
userID int,
|
||||
taskClasses []model.TaskClass,
|
||||
) (*newagenttools.ScheduleState, error) {
|
||||
) (*schedule.ScheduleState, error) {
|
||||
// 1. 确定规划窗口:优先使用 task class 日期范围,降级到当前周。
|
||||
windowDays, weeks := buildWindowFromTaskClasses(taskClasses)
|
||||
if len(windowDays) == 0 {
|
||||
@@ -236,7 +236,7 @@ func (p *ScheduleProvider) loadCompleteTaskClassesByIDs(
|
||||
}
|
||||
|
||||
// LoadTaskClassMetas 加载指定任务类的约束元数据(不含 Items、不含日程),供 Plan 阶段提前消费。
|
||||
func (p *ScheduleProvider) LoadTaskClassMetas(ctx context.Context, userID int, taskClassIDs []int) ([]newagenttools.TaskClassMeta, error) {
|
||||
func (p *ScheduleProvider) LoadTaskClassMetas(ctx context.Context, userID int, taskClassIDs []int) ([]schedule.TaskClassMeta, error) {
|
||||
if len(taskClassIDs) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
@@ -244,9 +244,9 @@ func (p *ScheduleProvider) LoadTaskClassMetas(ctx context.Context, userID int, t
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("加载任务类元数据失败: %w", err)
|
||||
}
|
||||
metas := make([]newagenttools.TaskClassMeta, 0, len(complete))
|
||||
metas := make([]schedule.TaskClassMeta, 0, len(complete))
|
||||
for _, tc := range complete {
|
||||
meta := newagenttools.TaskClassMeta{
|
||||
meta := schedule.TaskClassMeta{
|
||||
ID: tc.ID,
|
||||
Name: derefString(tc.Name),
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"sort"
|
||||
|
||||
"github.com/LoveLosita/smartflow/backend/model"
|
||||
newagenttools "github.com/LoveLosita/smartflow/backend/newAgent/tools"
|
||||
schedule "github.com/LoveLosita/smartflow/backend/newAgent/tools/schedule"
|
||||
)
|
||||
|
||||
// WindowDay 表示排课窗口中的一天(相对周 + 周几)。
|
||||
@@ -24,20 +24,20 @@ func LoadScheduleState(
|
||||
taskClasses []model.TaskClass,
|
||||
extraItemCategories map[int]string,
|
||||
windowDays []WindowDay,
|
||||
) *newagenttools.ScheduleState {
|
||||
state := &newagenttools.ScheduleState{
|
||||
Window: newagenttools.ScheduleWindow{
|
||||
) *schedule.ScheduleState {
|
||||
state := &schedule.ScheduleState{
|
||||
Window: schedule.ScheduleWindow{
|
||||
TotalDays: len(windowDays),
|
||||
DayMapping: make([]newagenttools.DayMapping, len(windowDays)),
|
||||
DayMapping: make([]schedule.DayMapping, len(windowDays)),
|
||||
},
|
||||
Tasks: make([]newagenttools.ScheduleTask, 0),
|
||||
Tasks: make([]schedule.ScheduleTask, 0),
|
||||
}
|
||||
|
||||
// 1. 构建 day_index 与 (week, day_of_week) 的双向转换基础索引。
|
||||
dayLookup := make(map[[2]int]int, len(windowDays))
|
||||
for i, wd := range windowDays {
|
||||
dayIndex := i + 1
|
||||
state.Window.DayMapping[i] = newagenttools.DayMapping{
|
||||
state.Window.DayMapping[i] = schedule.DayMapping{
|
||||
DayIndex: dayIndex,
|
||||
Week: wd.Week,
|
||||
DayOfWeek: wd.DayOfWeek,
|
||||
@@ -118,7 +118,7 @@ func LoadScheduleState(
|
||||
}
|
||||
|
||||
locked := event.Type == "course" && !event.CanBeEmbedded
|
||||
var slots []newagenttools.TaskSlot
|
||||
var slots []schedule.TaskSlot
|
||||
for _, g := range groups {
|
||||
if len(g.sections) == 0 {
|
||||
continue
|
||||
@@ -131,12 +131,12 @@ func LoadScheduleState(
|
||||
continue
|
||||
}
|
||||
if day, ok := dayLookup[[2]int{g.week, g.dayOfWeek}]; ok {
|
||||
slots = append(slots, newagenttools.TaskSlot{Day: day, SlotStart: start, SlotEnd: end})
|
||||
slots = append(slots, schedule.TaskSlot{Day: day, SlotStart: start, SlotEnd: end})
|
||||
}
|
||||
start, end = sec, sec
|
||||
}
|
||||
if day, ok := dayLookup[[2]int{g.week, g.dayOfWeek}]; ok {
|
||||
slots = append(slots, newagenttools.TaskSlot{Day: day, SlotStart: start, SlotEnd: end})
|
||||
slots = append(slots, schedule.TaskSlot{Day: day, SlotStart: start, SlotEnd: end})
|
||||
}
|
||||
}
|
||||
sort.Slice(slots, func(i, j int) bool {
|
||||
@@ -147,7 +147,7 @@ func LoadScheduleState(
|
||||
})
|
||||
|
||||
stateID := nextStateID
|
||||
state.Tasks = append(state.Tasks, newagenttools.ScheduleTask{
|
||||
state.Tasks = append(state.Tasks, schedule.ScheduleTask{
|
||||
StateID: stateID,
|
||||
Source: "event",
|
||||
SourceID: eventID,
|
||||
@@ -207,12 +207,12 @@ func LoadScheduleState(
|
||||
}
|
||||
|
||||
if hostStateID, ok := itemIDToEmbedHostStateID[item.ID]; ok {
|
||||
hostSlots := []newagenttools.TaskSlot(nil)
|
||||
hostSlots := []schedule.TaskSlot(nil)
|
||||
if hostTask := state.TaskByStateID(hostStateID); hostTask != nil {
|
||||
hostSlots = cloneTaskSlots(hostTask.Slots)
|
||||
}
|
||||
stateID := nextStateID
|
||||
state.Tasks = append(state.Tasks, newagenttools.ScheduleTask{
|
||||
state.Tasks = append(state.Tasks, schedule.ScheduleTask{
|
||||
StateID: stateID,
|
||||
Source: "task_item",
|
||||
SourceID: item.ID,
|
||||
@@ -230,7 +230,7 @@ func LoadScheduleState(
|
||||
|
||||
if slots, ok := slotsFromTargetTime(item.EmbeddedTime, dayLookup); ok {
|
||||
stateID := nextStateID
|
||||
state.Tasks = append(state.Tasks, newagenttools.ScheduleTask{
|
||||
state.Tasks = append(state.Tasks, schedule.ScheduleTask{
|
||||
StateID: stateID,
|
||||
Source: "task_item",
|
||||
SourceID: item.ID,
|
||||
@@ -251,7 +251,7 @@ func LoadScheduleState(
|
||||
}
|
||||
|
||||
stateID := nextStateID
|
||||
state.Tasks = append(state.Tasks, newagenttools.ScheduleTask{
|
||||
state.Tasks = append(state.Tasks, schedule.ScheduleTask{
|
||||
StateID: stateID,
|
||||
Source: "task_item",
|
||||
SourceID: item.ID,
|
||||
@@ -269,7 +269,7 @@ func LoadScheduleState(
|
||||
|
||||
// 仅当该任务类仍有 pending item 时,才把约束暴露给 LLM。
|
||||
if pendingCount > 0 {
|
||||
meta := newagenttools.TaskClassMeta{
|
||||
meta := schedule.TaskClassMeta{
|
||||
ID: tc.ID,
|
||||
Name: catName,
|
||||
}
|
||||
@@ -328,12 +328,12 @@ func LoadScheduleState(
|
||||
if cat, exists := itemCategoryLookup[itemID]; exists && cat != "" {
|
||||
category = cat
|
||||
}
|
||||
hostSlots := []newagenttools.TaskSlot(nil)
|
||||
hostSlots := []schedule.TaskSlot(nil)
|
||||
if hostTask != nil {
|
||||
hostSlots = cloneTaskSlots(hostTask.Slots)
|
||||
}
|
||||
guestStateID = nextStateID
|
||||
state.Tasks = append(state.Tasks, newagenttools.ScheduleTask{
|
||||
state.Tasks = append(state.Tasks, schedule.ScheduleTask{
|
||||
StateID: guestStateID,
|
||||
Source: "task_item",
|
||||
SourceID: itemID,
|
||||
@@ -412,7 +412,7 @@ func taskItemName(item model.TaskClassItem) string {
|
||||
func slotsFromTargetTime(
|
||||
target *model.TargetTime,
|
||||
dayLookup map[[2]int]int,
|
||||
) ([]newagenttools.TaskSlot, bool) {
|
||||
) ([]schedule.TaskSlot, bool) {
|
||||
if target == nil {
|
||||
return nil, false
|
||||
}
|
||||
@@ -423,7 +423,7 @@ func slotsFromTargetTime(
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
return []newagenttools.TaskSlot{
|
||||
return []schedule.TaskSlot{
|
||||
{
|
||||
Day: day,
|
||||
SlotStart: target.SectionFrom,
|
||||
@@ -471,8 +471,8 @@ type ScheduleChange struct {
|
||||
|
||||
// DiffScheduleState 比较 original 与 modified,返回需要持久化的变更集合。
|
||||
func DiffScheduleState(
|
||||
original *newagenttools.ScheduleState,
|
||||
modified *newagenttools.ScheduleState,
|
||||
original *schedule.ScheduleState,
|
||||
modified *schedule.ScheduleState,
|
||||
) []ScheduleChange {
|
||||
if original == nil || modified == nil {
|
||||
return nil
|
||||
@@ -534,8 +534,8 @@ func DiffScheduleState(
|
||||
}
|
||||
|
||||
// indexByStateID 将任务列表按 state_id 建立索引。
|
||||
func indexByStateID(state *newagenttools.ScheduleState) map[int]*newagenttools.ScheduleTask {
|
||||
m := make(map[int]*newagenttools.ScheduleTask, len(state.Tasks))
|
||||
func indexByStateID(state *schedule.ScheduleState) map[int]*schedule.ScheduleTask {
|
||||
m := make(map[int]*schedule.ScheduleTask, len(state.Tasks))
|
||||
for i := range state.Tasks {
|
||||
m[state.Tasks[i].StateID] = &state.Tasks[i]
|
||||
}
|
||||
@@ -543,7 +543,7 @@ func indexByStateID(state *newagenttools.ScheduleState) map[int]*newagenttools.S
|
||||
}
|
||||
|
||||
// slotsEqual 判断两个压缩槽位切片是否完全一致。
|
||||
func slotsEqual(a, b []newagenttools.TaskSlot) bool {
|
||||
func slotsEqual(a, b []schedule.TaskSlot) bool {
|
||||
if len(a) != len(b) {
|
||||
return false
|
||||
}
|
||||
@@ -556,18 +556,18 @@ func slotsEqual(a, b []newagenttools.TaskSlot) bool {
|
||||
}
|
||||
|
||||
// cloneTaskSlots 深拷贝槽位切片。
|
||||
func cloneTaskSlots(src []newagenttools.TaskSlot) []newagenttools.TaskSlot {
|
||||
func cloneTaskSlots(src []schedule.TaskSlot) []schedule.TaskSlot {
|
||||
if len(src) == 0 {
|
||||
return nil
|
||||
}
|
||||
dst := make([]newagenttools.TaskSlot, len(src))
|
||||
dst := make([]schedule.TaskSlot, len(src))
|
||||
copy(dst, src)
|
||||
return dst
|
||||
}
|
||||
|
||||
// resolveHostEventID 通过任务的 EmbedHost 反查宿主 event_id。
|
||||
// 非嵌入任务或宿主不存在时返回 0。
|
||||
func resolveHostEventID(task *newagenttools.ScheduleTask, state *newagenttools.ScheduleState) int {
|
||||
func resolveHostEventID(task *schedule.ScheduleTask, state *schedule.ScheduleState) int {
|
||||
if task == nil || task.EmbedHost == nil {
|
||||
return 0
|
||||
}
|
||||
@@ -579,7 +579,7 @@ func resolveHostEventID(task *newagenttools.ScheduleTask, state *newagenttools.S
|
||||
}
|
||||
|
||||
// expandToCoords 将压缩槽位展开成逐节坐标,便于后续持久化层处理。
|
||||
func expandToCoords(slots []newagenttools.TaskSlot, state *newagenttools.ScheduleState) []SlotCoord {
|
||||
func expandToCoords(slots []schedule.TaskSlot, state *schedule.ScheduleState) []SlotCoord {
|
||||
var coords []SlotCoord
|
||||
for _, slot := range slots {
|
||||
week, dow, ok := state.DayToWeekDay(slot.Day)
|
||||
|
||||
Reference in New Issue
Block a user