Version: 0.9.47.dev.260427

后端:
1. execute 节点继续拆职责——超大 execute.go 下沉为 node/execute 子包,按决策流、动作路由、上下文锚点、工具执行、状态快照、工具展示与参数解析拆分;顶层 execute.go 收敛为桥接导出,降低单文件编排/业务/模型/工具逻辑混写
2. 节点公共能力继续沉到 shared——抽出 LLM 纠错回灌、完整上下文调试日志、thinking 开关、统一上下文压缩、可见 assistant 文本持久化等 node_* 公共件,减少 execute 独占实现并为其他节点复用铺路
3. speak 文本整理能力独立收口——新增 speak_text 辅助文件,补齐正文归一化的独立承载,继续收缩 execute 主文件体积

前端:
4. NewAgent 时间线接入 business_card 业务卡片协议——schedule_agent.ts 新增 task_query / task_record 卡片载荷类型与 business_card kind;AssistantPanel 增加业务卡片事件存储、时间线恢复、块渲染分支与 BusinessCardRenderer 接入,同时保留 interrupt / status / tool / reasoning 多块并存
5. 新增任务查询卡片与任务记录卡片组件,并补充 DesignDemo 设计预览页与路由,前端可先行验证 business_card 的视觉与交互落点

文档:
6. 新增 newagent business card 前后端对接说明,明确 timeline kind、payload 结构、卡片分类、前后端发射/渲染约束
This commit is contained in:
LoveLosita
2026-04-27 17:35:55 +08:00
parent 736ba0cff3
commit 0b0ed3c61a
23 changed files with 4528 additions and 2966 deletions

View File

@@ -0,0 +1,121 @@
package newagentshared
import (
"encoding/json"
"fmt"
"log"
"strings"
newagentmodel "github.com/LoveLosita/smartflow/backend/newAgent/model"
"github.com/cloudwego/eino/schema"
)
// LogNodeLLMContext 将某个节点即将送入 LLM 的完整消息上下文按统一格式打印到日志。
//
// 步骤化说明:
// 1. 统一输出 stage / phase / chat / round方便按一次请求内的多次 LLM 调用串联排查;
// 2. 完整展开 messages不做截断保证问题复现时能直接对照 prompt 组装结果;
// 3. 该函数只负责调试日志,不参与任何业务判断,也不修改上下文内容。
func LogNodeLLMContext(
stage string,
phase string,
flowState *newagentmodel.CommonState,
messages []*schema.Message,
) {
chatID := ""
roundUsed := 0
if flowState != nil {
chatID = flowState.ConversationID
roundUsed = flowState.RoundUsed
}
log.Printf(
"[DEBUG] %s LLM context begin phase=%s chat=%s round=%d message_count=%d\n%s\n[DEBUG] %s LLM context end phase=%s chat=%s round=%d",
stage,
strings.TrimSpace(phase),
chatID,
roundUsed,
len(messages),
formatLLMMessagesForDebug(messages),
stage,
strings.TrimSpace(phase),
chatID,
roundUsed,
)
}
// formatLLMMessagesForDebug 将本轮送入 LLM 的完整消息上下文展开成可读多行日志。
//
// 说明:
// 1. 按消息索引逐条输出,便于和上游上下文构造步骤逐项对齐;
// 2. 完整输出 content / reasoning_content / tool_calls / extra不做截断
// 3. 仅用于调试打点,不参与业务决策。
func formatLLMMessagesForDebug(messages []*schema.Message) string {
if len(messages) == 0 {
return "(empty messages)"
}
var sb strings.Builder
for i, msg := range messages {
sb.WriteString(fmt.Sprintf("----- message[%d] -----\n", i))
if msg == nil {
sb.WriteString("role: <nil>\n\n")
continue
}
sb.WriteString(fmt.Sprintf("role: %s\n", msg.Role))
if strings.TrimSpace(msg.ToolCallID) != "" {
sb.WriteString(fmt.Sprintf("tool_call_id: %s\n", msg.ToolCallID))
}
if strings.TrimSpace(msg.ToolName) != "" {
sb.WriteString(fmt.Sprintf("tool_name: %s\n", msg.ToolName))
}
if len(msg.ToolCalls) > 0 {
sb.WriteString("tool_calls:\n")
for j, call := range msg.ToolCalls {
sb.WriteString(fmt.Sprintf(" - [%d] id=%s type=%s function=%s\n", j, call.ID, call.Type, call.Function.Name))
sb.WriteString(" arguments:\n")
sb.WriteString(indentMultilineForDebug(call.Function.Arguments, " "))
sb.WriteString("\n")
}
}
if strings.TrimSpace(msg.ReasoningContent) != "" {
sb.WriteString("reasoning_content:\n")
sb.WriteString(indentMultilineForDebug(msg.ReasoningContent, " "))
sb.WriteString("\n")
}
sb.WriteString("content:\n")
sb.WriteString(indentMultilineForDebug(msg.Content, " "))
sb.WriteString("\n")
if len(msg.Extra) > 0 {
sb.WriteString("extra:\n")
raw, err := json.MarshalIndent(msg.Extra, "", " ")
if err != nil {
sb.WriteString(indentMultilineForDebug("<marshal_error>", " "))
} else {
sb.WriteString(indentMultilineForDebug(string(raw), " "))
}
sb.WriteString("\n")
}
sb.WriteString("\n")
}
return sb.String()
}
// indentMultilineForDebug 为多行文本统一添加前缀缩进,避免日志折行后难以阅读。
func indentMultilineForDebug(text, prefix string) string {
if text == "" {
return prefix + "<empty>"
}
lines := strings.Split(text, "\n")
for i := range lines {
lines[i] = prefix + lines[i]
}
return strings.Join(lines, "\n")
}