Files
Agent-System/internal/app/resource_version_binder.go
weichen dbae19e80d fix(intentflow): bind resource versions for U10/U11 at plan create
Mutate/docgov live Authorize requires ExpectedResourceVersion; populate it
(and frame slots) when HandleTurn drafts confirm-class steps so confirm
no longer fails closed with PLAN_ACTION_VERSION_CONFLICT.
2026-09-23 15:44:48 +00:00

60 lines
1.6 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package app
import (
"context"
"encoding/json"
"strings"
"chat-agent-system/internal/app/intentflow"
"chat-agent-system/internal/docgov"
)
// newResourceVersionBinder binds optimistic versions for U10/U11 live keys at
// plan-create time so confirm-time Authorize sees ExpectedResourceVersion.
func newResourceVersionBinder(bb ProjectBlackboardPort, gov *docgov.GovernanceEngine) intentflow.ResourceVersionBinder {
return func(ctx context.Context, in intentflow.ResourceVersionBindInput) (string, error) {
switch in.ActionKey {
case mutateActionKey:
if bb.CurrentVersion == nil {
return "0", nil
}
return bb.CurrentVersion(ctx, in.Principal.ProjectID)
case "document.claim", "document.review.submit":
if gov == nil {
return "", intentflow.ErrPlanActionForbidden
}
docID := docIDFromSlotsOrSummary(in.Slots, in.SafeSummary)
if docID == "" {
return "", intentflow.ErrPlanActionForbidden
}
doc, err := gov.GetDocument(ctx, docID)
if err != nil || doc == nil {
return "", intentflow.ErrPlanActionForbidden
}
return docVersion(doc), nil
default:
return "", nil
}
}
}
func docIDFromSlotsOrSummary(slots []byte, summary string) string {
if len(slots) > 0 {
var m map[string]string
if json.Unmarshal(slots, &m) == nil {
if id := strings.TrimSpace(m["doc_id"]); id != "" {
return id
}
}
}
summary = strings.TrimSpace(summary)
// Prefer explicit doc_proj* tokens embedded in the utterance summary.
for _, tok := range strings.Fields(summary) {
tok = strings.Trim(tok, ",。,.;;::")
if strings.HasPrefix(tok, "doc_") {
return tok
}
}
return summary
}