Why: Account disable could be followed by late Backend business writes, API key creation could implicitly create users, account bootstrap locks could invert, and directory cursors were process-local or leaked out-of-scope changes. Evidence: Local go test ./... and isolated PostgreSQL package suites passed on the staged candidate; exact committed-head SELF replay and stage 6 human review remain pending. Impact: Adds final account transactions and external-effect checks across HTTP, Host, Bus and run manager; tightens API key issuance and persists versioned cursor signing. Delegated RDM rename still needs the separately proposed real-operator contract, so A1 and stage 6 are not complete. Refs: Documents U3 r1, approved A1-A4 amendment fb3a821, pending delegated-projection amendment 5783940, Dev feature/iam-u3-account-directory-recovery.
66 lines
2.0 KiB
Go
66 lines
2.0 KiB
Go
package runmgr
|
||
|
||
import (
|
||
core "agent-system-core"
|
||
)
|
||
|
||
// SetGenUIAuto 注入自动建议闸门(组合根装配;nil 关闭)。
|
||
func (m *Manager) SetGenUIAuto(a GenUIAutoTrigger) { m.genuiAuto = a }
|
||
|
||
// genUIAutoReminderText 与 genui.AutoReminder 文案保持同步(runmgr 不得依赖 genui 包)。
|
||
func genUIAutoReminderText() string {
|
||
return "任务语义事件已发生(阶段或材料/工件完成)。若 generative-ui 已启用,请调用一次 generative-ui.present 生成或修订建议页,按当前任务阶段组织信息。不要点击页面 actions,不要改写 plan/todo/任务完成状态;任务事实只能来自真实任务记录。"
|
||
}
|
||
|
||
// maybeGenUIAuto:语义事件钩子入口。仅同步追加 system-reminder,供后续回合消费;
|
||
// 不另起 notice-run(避免与在途 run / 测试拆卸竞态)。材料完成路径在
|
||
// startNoticeRun 内联注入同一文案。
|
||
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
|
||
}
|
||
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}},
|
||
}
|
||
_ = m.appendMessageForEffectiveAccount(owner, &msg)
|
||
}
|
||
|
||
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
|
||
}
|