ci / vet-and-test (pull_request) Successful in 1m4s
Why: Known-boundary follow-up: owner opt-in auto page suggestions on semantic task events without self-trigger from surface revisions. Evidence: go test ./internal/genui/ ./internal/runmgr/ ./internal/settings/ ./internal/app/ Impact: Default-off settings key; material/plan/todo/document hooks nudge present. Refs: docs/proposals/2026-10-12-generative-ui-auto-trigger.md Co-authored-by: Cursor <cursoragent@cursor.com>
85 lines
2.1 KiB
Go
85 lines
2.1 KiB
Go
package runmgr
|
||
|
||
import (
|
||
"agent-system-backend/internal/genui"
|
||
core "agent-system-core"
|
||
)
|
||
|
||
// SetGenUIAuto 注入自动建议闸门(组合根装配;nil 关闭)。
|
||
func (m *Manager) SetGenUIAuto(a GenUIAutoTrigger) { m.genuiAuto = a }
|
||
|
||
func genUIAutoReminderText() string { return genui.AutoReminder }
|
||
|
||
// maybeGenUIAuto:语义事件钩子入口。会话忙碌时只追加 system 消息供下一轮消费;
|
||
// 空闲时启动短 notice-run 让模型有机会立即 present。
|
||
func (m *Manager) maybeGenUIAuto(owner, convID, reason string) {
|
||
if m == nil || m.genuiAuto == nil {
|
||
return
|
||
}
|
||
ok, _ := m.genuiAuto.Try(owner, convID, reason)
|
||
if !ok {
|
||
return
|
||
}
|
||
go m.deliverGenUIAutoReminder(owner, convID, reason)
|
||
}
|
||
|
||
func (m *Manager) deliverGenUIAutoReminder(owner, convID, reason string) {
|
||
text := "<system-reminder>\n" + genUIAutoReminderText() + "\n(trigger=" + reason + ")\n</system-reminder>"
|
||
msg := core.Message{
|
||
ConversationID: convID, Role: core.RoleSystem,
|
||
Parts: []core.Part{{Type: core.PartText, Text: text}},
|
||
}
|
||
if err := m.st.AppendMessage(&msg); err != nil {
|
||
return
|
||
}
|
||
m.convMu.Lock()
|
||
busy := m.convActive[convID]
|
||
m.convMu.Unlock()
|
||
if busy {
|
||
return
|
||
}
|
||
conv, err := m.st.GetConversation(owner, convID)
|
||
if err != nil {
|
||
return
|
||
}
|
||
if err := m.claimConversation(convID); err != nil {
|
||
return
|
||
}
|
||
if _, err := m.startClaimedRun(conv, msg, nil, nil, nil); err != nil {
|
||
m.releaseConversation(convID)
|
||
}
|
||
}
|
||
|
||
func planStageChanged(prev, next core.PlanSnapshot) bool {
|
||
pm := map[string]string{}
|
||
for _, s := range prev.Steps {
|
||
pm[s.ID] = string(s.Status)
|
||
}
|
||
for _, s := range next.Steps {
|
||
if pm[s.ID] != string(s.Status) {
|
||
return true
|
||
}
|
||
}
|
||
// 新增步骤也视为阶段组织变化
|
||
if len(next.Steps) > len(prev.Steps) {
|
||
return true
|
||
}
|
||
return false
|
||
}
|
||
|
||
func todoStageChanged(prev, next core.TodoList) bool {
|
||
pm := map[string]string{}
|
||
for _, t := range prev.Items {
|
||
pm[t.ID] = string(t.Status)
|
||
}
|
||
for _, t := range next.Items {
|
||
if pm[t.ID] != string(t.Status) {
|
||
return true
|
||
}
|
||
}
|
||
if len(next.Items) > len(prev.Items) {
|
||
return true
|
||
}
|
||
return false
|
||
}
|