Files
Agent-System/internal/app/wire_supplement_impact.go
T
weichen b5a782bb38 feat(chat): dialogue triggers for comments/reopen/pending-supplements with mistouch guards
Wire intent→coordinator DocResolver confirm cards→action_executor kinds for comment, reopen, pending-supplements query, and real submit-review execution.
2026-09-25 20:14:10 +00:00

102 lines
3.4 KiB
Go

package app
import (
"context"
"fmt"
"log/slog"
"time"
"chat-agent-system/internal/app/docnotify"
"chat-agent-system/internal/docgov"
"chat-agent-system/internal/intent"
"chat-agent-system/internal/notification"
"chat-agent-system/internal/supplementimpact"
)
func (r *Runtime) wireSupplementImpact() {
if r == nil || r.Pool == nil || r.Gov == nil || r.Trace == nil {
return
}
if r.SupplementImpact != nil {
return
}
svc := &supplementimpact.Service{
Store: supplementimpact.NewPGStore(r.Pool),
Docs: r.Gov,
Analyze: r.Trace,
Notify: r.Notify,
Propose: r.Gov,
Pending: r.Gov,
}
r.SupplementImpact = svc
if r.Biz != nil && r.Notify != nil {
r.Biz.SetDigestNotifier(r.Notify)
}
if r.Gov != nil && r.Notify != nil {
r.Gov.SetPendingDigestNotify(func(ctx context.Context, doc *docgov.DocumentRecord, pending []docgov.PendingSupplement) {
if doc == nil || doc.AuthorID <= 0 || len(pending) == 0 {
return
}
summary := pending[0].SourceSummary
if summary == "" {
summary = fmt.Sprintf("%d 条积压补充", len(pending))
}
_ = r.Notify.UpsertDocumentDigest(ctx, notification.UpsertDigestParams{
UserID: doc.AuthorID, ProjectID: doc.ProjectID,
DigestKind: notification.DigestKindPendingSupplements,
DocID: doc.DocID, DocTitle: doc.Title,
Severity: notification.SeverityActionRequired,
Summary: summary,
})
})
r.Gov.SetLifecycleNotify(func(ctx context.Context, action string, doc *docgov.DocumentRecord, actorID int64, actorName, detail string) {
docnotify.EmitLifecycle(ctx, docnotify.EmitLifecycleParams{
Notify: r.Notify, Digest: r.Notify, Chat: r.Ctx,
Action: docnotify.LifecycleAction(action), Doc: doc,
ActorID: actorID, ActorName: actorName, Detail: detail,
})
})
}
if r.Engine != nil {
r.Engine.SetOnSupplement(func(ctx context.Context, projectID, userID int64, sessionID, summary, markdown string) {
b, err := svc.CreateFromSupplement(ctx, projectID, userID, sessionID, summary, markdown)
if err != nil {
slog.Warn("supplementimpact sync create failed", "error", err, "project_id", projectID)
return
}
r.Engine.SetPendingSupplementCard(batchToCard(b))
})
}
if r.mutateOwner != nil {
r.mutateOwner.OnSupplement = func(ctx context.Context, projectID, userID int64, sessionID, summary, markdown string) {
supplementimpact.TriggerAsync(svc, projectID, userID, sessionID, summary, markdown)
}
}
}
func batchToCard(b *supplementimpact.Batch) *intent.InteractiveCardPayload {
if b == nil {
return nil
}
title, summary := supplementimpact.BuildConfirmCardMeta(b)
actions := []intent.CardAction{
{ActionID: "confirm_supplement_impact", Label: "确认更新所选文档", Style: "primary", IsAffirmativeDefault: true},
{ActionID: "cancel_supplement_impact", Label: "取消", Style: "subtle"},
}
body := summary + "\n" + fmt.Sprintf("batch_id=%s\nnonce=%s\nrevision=%d\ncoverage=%s", b.BatchID, b.DecisionNonce, b.Revision, b.CoverageStatus)
for _, it := range b.Items {
body += fmt.Sprintf("\n- %s | claimed=%v busy=%v locked=%v | %s", it.DocID, it.AuthorClaimedSnapshot, it.BusySnapshot, it.LockedSnapshot, it.Title)
}
return &intent.InteractiveCardPayload{
CardID: b.BatchID,
CardType: "SUPPLEMENT_IMPACT_CONFIRM",
Title: title,
ProposedContent: body,
ImpactRisk: b.CoverageStatus,
CurrentStatus: "active",
TTLTurns: 8,
CreatedAt: time.Now().UTC(),
Actions: actions,
}
}