feat(agent): Agent 工作台 - 计划插话记忆、统一模型选择器并修复摘要与视频入库
将计划清单、运行中插话和个人记忆接入云端 Agent;全站模型选择器统一为左右二级菜单。画布摘要按预算截断不再整轮拒绝,首页视频未知宽高可入库。README 补充贡献者 morrow。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
89
backend/internal/app/cloud_agent_working_context.go
Normal file
89
backend/internal/app/cloud_agent_working_context.go
Normal file
@@ -0,0 +1,89 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
cloudAgentHistoryKeepRounds = 10
|
||||
cloudAgentHistoryMaxBytes = 64000
|
||||
)
|
||||
|
||||
func isCloudAgentContinuationMessage(message providerTextMessage) bool {
|
||||
if message.Role != "user" {
|
||||
return false
|
||||
}
|
||||
content := strings.TrimSpace(message.Content)
|
||||
return strings.HasPrefix(content, "上一轮真实执行记录") || strings.HasPrefix(content, "上一轮已结束")
|
||||
}
|
||||
|
||||
func cloudAgentHistoryUserInstructionCount(history []providerTextMessage) int {
|
||||
count := 0
|
||||
for _, message := range history {
|
||||
if message.Role == "user" && !isCloudAgentContinuationMessage(message) {
|
||||
count++
|
||||
}
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
func cloudAgentHistoryJSONSize(history []providerTextMessage) int {
|
||||
raw, err := json.Marshal(history)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return len(raw)
|
||||
}
|
||||
|
||||
func dropOldestCloudAgentHistoryRound(history []providerTextMessage) []providerTextMessage {
|
||||
if len(history) == 0 {
|
||||
return history
|
||||
}
|
||||
if isCloudAgentContinuationMessage(history[0]) || history[0].Role != "user" {
|
||||
return history[1:]
|
||||
}
|
||||
index := 1
|
||||
for index < len(history) {
|
||||
if history[index].Role == "user" && !isCloudAgentContinuationMessage(history[index]) {
|
||||
break
|
||||
}
|
||||
index++
|
||||
}
|
||||
return history[index:]
|
||||
}
|
||||
|
||||
// trimCloudAgentTextHistory 只把最近若干轮用户对话留给模型。
|
||||
// 个人记忆、更早轮次和上一轮工具流水不进工作上下文;超字节上限时从最旧一轮往下丢。
|
||||
func trimCloudAgentTextHistory(history []providerTextMessage, keepRounds, maxBytes int) []providerTextMessage {
|
||||
if keepRounds <= 0 {
|
||||
keepRounds = cloudAgentHistoryKeepRounds
|
||||
}
|
||||
if maxBytes <= 0 {
|
||||
maxBytes = cloudAgentHistoryMaxBytes
|
||||
}
|
||||
if len(history) == 0 {
|
||||
return history
|
||||
}
|
||||
start := 0
|
||||
seen := 0
|
||||
for index := len(history) - 1; index >= 0; index-- {
|
||||
if history[index].Role != "user" || isCloudAgentContinuationMessage(history[index]) {
|
||||
continue
|
||||
}
|
||||
seen++
|
||||
if seen == keepRounds {
|
||||
start = index
|
||||
break
|
||||
}
|
||||
}
|
||||
trimmed := append([]providerTextMessage{}, history[start:]...)
|
||||
for cloudAgentHistoryJSONSize(trimmed) > maxBytes && cloudAgentHistoryUserInstructionCount(trimmed) > 1 {
|
||||
next := dropOldestCloudAgentHistoryRound(trimmed)
|
||||
if len(next) >= len(trimmed) {
|
||||
break
|
||||
}
|
||||
trimmed = next
|
||||
}
|
||||
return trimmed
|
||||
}
|
||||
Reference in New Issue
Block a user