Files
smartmate/backend/newAgent/prompt/deliver_window.go
Losita b309a32a98 Version: 0.9.33.dev.260419
后端:
1. deliver 收口上下文重构——历史折叠到工作区,仅基于本轮 execute 窗口诚实收口
  - newAgent/prompt/deliver.go:BuildDeliverMessages 改为向 buildDeliverWorkspace 透传 ConversationContext
  - newAgent/prompt/deliver_context.go:deliver 的 msg1 改为轻量提示,不再回灌完整历史;msg2 追加本轮 execute 窗口与结果态信息

前端:
2. 品牌命名统一切换为 SmartMate
  - index.html:页面标题从 SmartFlow 改为 SmartMate
  - package.json:前端包名改为 smartmate-frontend
  - App.vue:布局类名从 smartflow-* 统一改为 smartmate-*
  - stores/auth.ts:access/refresh token 与 last username 的 localStorage key 全部切到 smartmate_*
  - utils/idempotency.ts:默认幂等键前缀从 smartflow 改为 smartmate
  - DashboardView.vue:首页默认问候名从 SmartFlow 用户改为 SmartMate 用户
3. 助手页体验重做——默认空会话、排程卡片懒加载、上下文统计刷新时机收口
  - components/dashboard/AssistantPanel.vue:进入页面不再自动打开最后一次会话,改为展示居中欢迎空态
  - components/dashboard/AssistantPanel.vue:schedule_completed 改为先展示占位卡片,点击后再拉取 schedule preview,避免预览未落库时并发 404
  - components/dashboard/AssistantPanel.vue:tool done、schedule card、SSE block done、[DONE] 与整轮流结束后统一刷新 context stats
  - components/dashboard/AssistantPanel.vue:重构聊天区布局、空态欢迎内容、底部交互区与内外边距,整体视觉切到更轻的阅读式界面
  - views/AssistantView.vue:移除外层白底卡片壳,交由 AssistantPanel 自己承接容器视觉
4. 排程微调保存链路补幂等保护,并修正请求头口径
  - api/schedule_agent.ts:正式应用接口请求头从 Idempotency-Key 改为 X-Idempotency-Key
  - components/assistant/ScheduleFineTuneModal.vue:同一预览会话复用稳定幂等键,保存成功后再刷新新 key,避免重试或延迟导致重复落库
  - components/assistant/ScheduleResultCard.vue:结果卡片样式、hover 与进场动效整体升级
5. 任务类选择器与侧边导航细节调整
  - components/assistant/TaskClassPlanningPicker.vue:popover、骨架屏、列表项、选中态与按钮视觉整体重绘
  - components/common/MainSidebar.vue:移除“任务”占位入口,侧栏只保留总览 / 日程 / 助手
6. 登录页与首页展示风格重做
  - views/AuthView.vue:品牌文案切到 SmartMate,登录/注册从 tabs 改为自定义双态切换,重做背景、玻璃卡片、表单与动效
  - views/DashboardView.vue:首页主区改为 auto + 1fr 布局,锁定顶部栏高度,避免缩放时形变

仓库:
7. README 全量更新到当前版本能力边界
  - README.md:重写项目定位、功能描述、业务闭环图、newAgent graph 流程、工具定义、前端衔接边界、页面展示、部署方案与监控说明
2026-04-19 23:54:48 +08:00

104 lines
3.8 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package newagentprompt
import (
"fmt"
"strings"
newagentmodel "github.com/LoveLosita/smartflow/backend/newAgent/model"
"github.com/cloudwego/eino/schema"
)
const deliverHistoryKindExecuteLoopClosed = "execute_loop_closed"
// sliceHistoryAfterLastExecuteLoopClosed 基于最后一个 execute_loop_closed 标记切出当前活跃窗口。
//
// 步骤化说明:
// 1. 先读取完整 history 快照,避免直接在 ConversationContext 原地切片,减少后续调用方误改底层数组的风险;
// 2. 从后往前找最后一个 execute_loop_closed确保拿到的是“最近一次已正常收口”的边界
// 3. 命中边界后只返回边界之后的消息,这样 deliver 看到的就是当前活跃轮次;
// 4. 若完全没有边界,说明会话尚未形成稳定闭环,此时退回全量 history避免误丢当前活跃上下文。
func sliceHistoryAfterLastExecuteLoopClosed(ctx *newagentmodel.ConversationContext) []*schema.Message {
if ctx == nil {
return nil
}
history := ctx.HistorySnapshot()
if len(history) == 0 {
return nil
}
cut := -1
for i := len(history) - 1; i >= 0; i-- {
if isDeliverExecuteLoopClosedMarker(history[i]) {
cut = i
break
}
}
if cut < 0 {
return history
}
if cut+1 >= len(history) {
return nil
}
return history[cut+1:]
}
// isDeliverExecuteLoopClosedMarker 判断一条历史消息是否为 execute loop 正常收口边界。
//
// 职责边界:
// 1. 这里只识别 prompt 层真正关心的 execute_loop_closed 标记;
// 2. 不负责推断其他中断/恢复语义,避免把 confirm/ask_user 等同一轮过程误判成新边界;
// 3. 若消息结构不完整,则统一按“非边界”处理,保证切窗策略保守可回退。
func isDeliverExecuteLoopClosedMarker(msg *schema.Message) bool {
if msg == nil || msg.Extra == nil {
return false
}
kind, ok := msg.Extra[executeHistoryKindKey].(string)
if !ok {
return false
}
return strings.TrimSpace(kind) == deliverHistoryKindExecuteLoopClosed
}
// buildDeliverExecuteWindow 基于当前活跃 history 窗口渲染 deliver 节点要看的执行事实视图。
//
// 步骤化说明:
// 1. 先按 execute_loop_closed 切掉旧轮次,只保留当前仍活跃的执行窗口;
// 2. 再分别抽取“本轮真实对话流”和“本轮 ReAct 工具事实链”,避免 deliver 回看旧 deliver 总结;
// 3. 若本轮还没有工具调用,也要明确告诉模型“当前无工具事实”,避免它擅自脑补;
// 4. 整段文本只服务 deliver.msg2不改变四段式骨架也不回写任何状态。
func buildDeliverExecuteWindow(ctx *newagentmodel.ConversationContext) string {
lines := []string{"本轮 execute 窗口:"}
historyWindow := sliceHistoryAfterLastExecuteLoopClosed(ctx)
if len(historyWindow) == 0 {
lines = append(lines, "- 当前没有可用的本轮执行窗口,请仅依据结果态工作区诚实收口。")
return strings.Join(lines, "\n")
}
turns := collectExecuteConversationTurns(historyWindow)
if len(turns) == 0 {
lines = append(lines, "- 本轮对话流:暂无。")
} else {
lines = append(lines, "本轮对话流:")
for _, turn := range turns {
lines = append(lines, fmt.Sprintf("- %s: %q", turn.Role, turn.Content))
}
}
loops := collectExecuteLoopRecords(historyWindow)
if len(loops) == 0 {
lines = append(lines, "- 本轮 ReAct 记录:暂无工具调用。")
return strings.Join(lines, "\n")
}
lines = append(lines, "本轮 ReAct 记录:")
for i, loop := range loops {
lines = append(lines, fmt.Sprintf("%d. thought/reason%s", i+1, loop.Thought))
lines = append(lines, fmt.Sprintf(" tool_call%s", renderExecuteToolCallText(loop.ToolName, loop.ToolArgs)))
lines = append(lines, fmt.Sprintf(" observation%s", loop.Observation))
}
return strings.Join(lines, "\n")
}