scorpio d6df056687 feat: Part 模型 + 文件版本追踪 + 写手团队工作流 v2
- 数据层:messages 表增加 part_type 字段,新建 file_versions 表支持版本追踪
- 后端:saveWorkspace 版本追踪、saveAgentOutput 源头分离、generateBriefMessage 成员简报
- 后端:applyDocumentEdit 增量编辑、buildWorkflowStep phase-aware 工作流引擎
- API:文件版本查询/回退接口
- 前端:part_type 驱动渲染,产物面板版本历史
- 新增写手团队(主编/搜索员/策划编辑/合规审查员)配置
- store 模块、scheduler 模块、web-search skill

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 18:44:34 +08:00

122 lines
3.2 KiB
Go

package store
type Message struct {
ID int64
RoomID string
Agent string
Role string
Content string
Filename string
Title string
GroupID *int64
CreatedAt string
PartType string
}
type FileVersion struct {
ID int64
RoomID string
Filename string
Content string
Agent string
Version int
CreatedAt string
}
func (s *Store) InsertMessage(msg *Message) (int64, error) {
s.mu.Lock()
defer s.mu.Unlock()
partType := msg.PartType
if partType == "" {
partType = "text"
}
res, err := s.db.Exec(
`INSERT INTO messages (room_id, agent, role, content, filename, title, group_id, part_type) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
msg.RoomID, msg.Agent, msg.Role, msg.Content, nilIfEmpty(msg.Filename), nilIfEmpty(msg.Title), msg.GroupID, partType,
)
if err != nil {
return 0, err
}
return res.LastInsertId()
}
func (s *Store) GetMessages(roomID string, limit, offset int) ([]Message, error) {
if limit <= 0 {
limit = 200
}
rows, err := s.db.Query(
`SELECT id, room_id, agent, role, content, COALESCE(filename,''), COALESCE(title,''), group_id, created_at, COALESCE(part_type,'text')
FROM messages WHERE room_id = ? ORDER BY created_at ASC, id ASC LIMIT ? OFFSET ?`,
roomID, limit, offset,
)
if err != nil {
return nil, err
}
defer rows.Close()
var msgs []Message
for rows.Next() {
var m Message
if err := rows.Scan(&m.ID, &m.RoomID, &m.Agent, &m.Role, &m.Content, &m.Filename, &m.Title, &m.GroupID, &m.CreatedAt, &m.PartType); err != nil {
return nil, err
}
msgs = append(msgs, m)
}
return msgs, nil
}
func (s *Store) InsertFileVersion(roomID, filename, content, agent string) (int64, error) {
s.mu.Lock()
defer s.mu.Unlock()
// 获取当前最大版本号
var maxVer int
s.db.QueryRow(`SELECT COALESCE(MAX(version), 0) FROM file_versions WHERE room_id = ? AND filename = ?`, roomID, filename).Scan(&maxVer)
res, err := s.db.Exec(
`INSERT INTO file_versions (room_id, filename, content, agent, version) VALUES (?, ?, ?, ?, ?)`,
roomID, filename, content, agent, maxVer+1,
)
if err != nil {
return 0, err
}
return res.LastInsertId()
}
func (s *Store) GetFileVersions(roomID, filename string) ([]FileVersion, error) {
rows, err := s.db.Query(
`SELECT id, room_id, filename, content, agent, version, created_at FROM file_versions WHERE room_id = ? AND filename = ? ORDER BY version DESC`,
roomID, filename,
)
if err != nil {
return nil, err
}
defer rows.Close()
var versions []FileVersion
for rows.Next() {
var v FileVersion
if err := rows.Scan(&v.ID, &v.RoomID, &v.Filename, &v.Content, &v.Agent, &v.Version, &v.CreatedAt); err != nil {
return nil, err
}
versions = append(versions, v)
}
return versions, nil
}
func (s *Store) GetFileVersion(roomID, filename string, version int) (*FileVersion, error) {
var v FileVersion
err := s.db.QueryRow(
`SELECT id, room_id, filename, content, agent, version, created_at FROM file_versions WHERE room_id = ? AND filename = ? AND version = ?`,
roomID, filename, version,
).Scan(&v.ID, &v.RoomID, &v.Filename, &v.Content, &v.Agent, &v.Version, &v.CreatedAt)
if err != nil {
return nil, err
}
return &v, nil
}
func nilIfEmpty(s string) interface{} {
if s == "" {
return nil
}
return s
}