Files
Agent-System/internal/intent/registry.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

193 lines
12 KiB
Go

package intent
import (
"fmt"
"sync"
)
// RiskLevel 动作风险等级
type RiskLevel string
const (
RiskLow RiskLevel = "low"
RiskMedium RiskLevel = "medium"
RiskHigh RiskLevel = "high"
)
// ActionAlias 自然语言别名
type ActionAlias struct {
Phrase string `json:"phrase"`
Acts []DialogueAct `json:"acts,omitempty"`
}
// SlotSpec 槽位规格
type SlotSpec struct {
Key string `json:"key"`
Required bool `json:"required"`
Label string `json:"label,omitempty"`
}
// ActionSpec 可识别、可授权、可执行的动作单一事实源
type ActionSpec struct {
Key string `json:"key"`
Domain string `json:"domain"`
Object string `json:"object"`
Goal GoalType `json:"goal"`
Risk RiskLevel `json:"risk"`
Aliases []ActionAlias `json:"aliases,omitempty"`
DialogueActs []DialogueAct `json:"dialogue_acts,omitempty"`
RequiredSlots []SlotSpec `json:"required_slots,omitempty"`
OptionalSlots []SlotSpec `json:"optional_slots,omitempty"`
CapabilityKey string `json:"capability_key,omitempty"`
AllowedStates []string `json:"allowed_states,omitempty"`
RequiresConfirm bool `json:"requires_confirm,omitempty"`
IdempotencyMode string `json:"idempotency_mode,omitempty"`
LegacyIntent IntentType `json:"legacy_intent"`
}
// ActionRegistry 动作注册表
type ActionRegistry struct {
mu sync.RWMutex
byKey map[string]*ActionSpec
byLegacy map[IntentType]*ActionSpec
}
var defaultRegistry *ActionRegistry
func init() {
defaultRegistry = NewActionRegistry()
registerBuiltinActions(defaultRegistry)
}
// DefaultRegistry 返回全局内置注册表
func DefaultRegistry() *ActionRegistry {
return defaultRegistry
}
// NewActionRegistry 创建空注册表
func NewActionRegistry() *ActionRegistry {
return &ActionRegistry{
byKey: make(map[string]*ActionSpec),
byLegacy: make(map[IntentType]*ActionSpec),
}
}
// Register 注册动作规格
func (r *ActionRegistry) Register(spec ActionSpec) error {
r.mu.Lock()
defer r.mu.Unlock()
if spec.Key == "" {
return fmt.Errorf("action spec key is required")
}
if spec.LegacyIntent == "" {
return fmt.Errorf("action spec %s: legacy_intent is required", spec.Key)
}
if existing, ok := r.byKey[spec.Key]; ok && existing.LegacyIntent != spec.LegacyIntent {
return fmt.Errorf("duplicate action key %s", spec.Key)
}
cp := spec
r.byKey[spec.Key] = &cp
r.byLegacy[spec.LegacyIntent] = &cp
return nil
}
// Get 按 action_key 查找
func (r *ActionRegistry) Get(key string) (*ActionSpec, bool) {
r.mu.RLock()
defer r.mu.RUnlock()
spec, ok := r.byKey[key]
return spec, ok
}
// GetByLegacyIntent 按旧 IntentType 查找
func (r *ActionRegistry) GetByLegacyIntent(t IntentType) (*ActionSpec, bool) {
r.mu.RLock()
defer r.mu.RUnlock()
spec, ok := r.byLegacy[t]
return spec, ok
}
// All 返回全部已注册动作
func (r *ActionRegistry) All() []*ActionSpec {
r.mu.RLock()
defer r.mu.RUnlock()
out := make([]*ActionSpec, 0, len(r.byKey))
for _, s := range r.byKey {
out = append(out, s)
}
return out
}
// CapabilityKeys 派生能力键列表(供 AvailableActions 同源生成)
func (r *ActionRegistry) CapabilityKeys() []string {
r.mu.RLock()
defer r.mu.RUnlock()
seen := make(map[string]struct{})
var keys []string
for _, s := range r.byKey {
if s.CapabilityKey == "" {
continue
}
if _, ok := seen[s.CapabilityKey]; ok {
continue
}
seen[s.CapabilityKey] = struct{}{}
keys = append(keys, s.CapabilityKey)
}
return keys
}
func registerBuiltinActions(r *ActionRegistry) {
specs := []ActionSpec{
{Key: "project.advisory", Domain: "project", Object: "project", Goal: GoalQuery, Risk: RiskLow, LegacyIntent: IntentQueryProgress, CapabilityKey: "QUERY_PROGRESS", DialogueActs: []DialogueAct{DialogueActAsk}},
{Key: "project.fact.supplement", Domain: "project", Object: "project_fact", Goal: GoalMutate, Risk: RiskMedium, LegacyIntent: IntentSupplementInfo, CapabilityKey: "SUPPLEMENT_INFO", DialogueActs: []DialogueAct{DialogueActCommand}},
{Key: "project.stage.advance", Domain: "project", Object: "project", Goal: GoalControl, Risk: RiskHigh, LegacyIntent: IntentAdvanceStage, CapabilityKey: "ADVANCE_STAGE", RequiresConfirm: true, DialogueActs: []DialogueAct{DialogueActCommand, DialogueActConfirm}},
{Key: "task.run", Domain: "project", Object: "task", Goal: GoalGenerate, Risk: RiskMedium, LegacyIntent: IntentTriggerTask, CapabilityKey: "TRIGGER_TASK", DialogueActs: []DialogueAct{DialogueActCommand}},
{Key: "task.run.adhoc", Domain: "project", Object: "task", Goal: GoalGenerate, Risk: RiskMedium, LegacyIntent: IntentTriggerAdhocTask, CapabilityKey: "TRIGGER_ADHOC_TASK"},
{Key: "conversation.chat", Domain: "conversation", Object: "system_ui", Goal: GoalConverse, Risk: RiskLow, LegacyIntent: IntentCasualChat},
{Key: "conversation.decline", Domain: "conversation", Object: "system_ui", Goal: GoalDecide, Risk: RiskLow, LegacyIntent: IntentDeclineExpectation, DialogueActs: []DialogueAct{DialogueActDecline}},
{Key: "document.claim", Domain: "document_gov", Object: "controlled_document", Goal: GoalMutate, Risk: RiskMedium, LegacyIntent: IntentDocGovClaim, CapabilityKey: "DOCGOV_CLAIM", DialogueActs: []DialogueAct{DialogueActCommand}},
{Key: "document.review.submit", Domain: "document_gov", Object: "controlled_document", Goal: GoalMutate, Risk: RiskMedium, LegacyIntent: IntentDocGovSubmitReview, CapabilityKey: "DOCGOV_SUBMIT_REVIEW", DialogueActs: []DialogueAct{DialogueActCommand}},
{Key: "document.review.approve", Domain: "document_gov", Object: "controlled_document", Goal: GoalMutate, Risk: RiskHigh, LegacyIntent: IntentDocGovReviewApprove, RequiresConfirm: true, DialogueActs: []DialogueAct{DialogueActCommand, DialogueActConfirm}},
{Key: "document.review.reject", Domain: "document_gov", Object: "controlled_document", Goal: GoalMutate, Risk: RiskHigh, LegacyIntent: IntentDocGovReviewReject, RequiresConfirm: true, RequiredSlots: []SlotSpec{{Key: SlotRejectReason, Required: true, Label: "驳回理由"}}, DialogueActs: []DialogueAct{DialogueActCommand}},
{Key: "document.final.approve", Domain: "document_gov", Object: "controlled_document", Goal: GoalMutate, Risk: RiskHigh, LegacyIntent: IntentDocGovFinalApprove, RequiresConfirm: true, DialogueActs: []DialogueAct{DialogueActCommand, DialogueActConfirm}},
{Key: "document.final.reject", Domain: "document_gov", Object: "controlled_document", Goal: GoalMutate, Risk: RiskHigh, LegacyIntent: IntentDocGovFinalReject, RequiresConfirm: true, RequiredSlots: []SlotSpec{{Key: SlotRejectReason, Required: true, Label: "驳回理由"}}, DialogueActs: []DialogueAct{DialogueActCommand}},
{Key: "document.proposal.decide", Domain: "document_gov", Object: "controlled_document", Goal: GoalDecide, Risk: RiskMedium, LegacyIntent: IntentDocGovProposalDecide, DialogueActs: []DialogueAct{DialogueActConfirm, DialogueActDecline}},
{Key: "document.comment.add", Domain: "document_gov", Object: "controlled_document", Goal: GoalMutate, Risk: RiskMedium, LegacyIntent: IntentDocGovCommentAdd, CapabilityKey: "DOCGOV_COMMENT_ADD", RequiresConfirm: true, RequiredSlots: []SlotSpec{{Key: SlotCommentContent, Required: true, Label: "批注内容"}}, DialogueActs: []DialogueAct{DialogueActCommand}},
{Key: "document.comment.resolve", Domain: "document_gov", Object: "controlled_document", Goal: GoalMutate, Risk: RiskMedium, LegacyIntent: IntentDocGovCommentResolve, CapabilityKey: "DOCGOV_COMMENT_RESOLVE", RequiresConfirm: true, DialogueActs: []DialogueAct{DialogueActCommand}},
{Key: "document.reopen.request", Domain: "document_gov", Object: "controlled_document", Goal: GoalMutate, Risk: RiskHigh, LegacyIntent: IntentDocGovReopenRequest, CapabilityKey: "DOCGOV_REOPEN_REQUEST", RequiresConfirm: true, RequiredSlots: []SlotSpec{{Key: SlotReopenReason, Required: true, Label: "重开原因"}}, DialogueActs: []DialogueAct{DialogueActCommand}},
{Key: "document.reopen.approve", Domain: "document_gov", Object: "controlled_document", Goal: GoalMutate, Risk: RiskHigh, LegacyIntent: IntentDocGovReopenApprove, CapabilityKey: "DOCGOV_REOPEN_APPROVE", RequiresConfirm: true, DialogueActs: []DialogueAct{DialogueActCommand, DialogueActConfirm}},
{Key: "document.pending_supplements.query", Domain: "document_gov", Object: "controlled_document", Goal: GoalQuery, Risk: RiskLow, LegacyIntent: IntentQueryPendingSupplements, CapabilityKey: "QUERY_PENDING_SUPPLEMENTS", DialogueActs: []DialogueAct{DialogueActAsk, DialogueActCommand}},
{Key: "regulation.query", Domain: "knowledge", Object: "regulation", Goal: GoalQuery, Risk: RiskLow, LegacyIntent: IntentQueryRegulations, CapabilityKey: "QUERY_REGULATIONS", DialogueActs: []DialogueAct{DialogueActAsk}},
{Key: "case.query", Domain: "knowledge", Object: "artifact", Goal: GoalQuery, Risk: RiskLow, LegacyIntent: IntentQuerySimilarCases, CapabilityKey: "QUERY_SIMILAR_CASES", DialogueActs: []DialogueAct{DialogueActAsk}},
{Key: "permission.query", Domain: "project", Object: "user_permission", Goal: GoalQuery, Risk: RiskLow, LegacyIntent: IntentQueryUserRights, CapabilityKey: "QUERY_USER_RIGHTS", DialogueActs: []DialogueAct{DialogueActAsk}},
{Key: "document.reject_reason.query", Domain: "document_gov", Object: "controlled_document", Goal: GoalQuery, Risk: RiskLow, LegacyIntent: IntentQueryRejectReason, DialogueActs: []DialogueAct{DialogueActAsk}},
{Key: "card.confirm", Domain: "conversation", Object: "system_ui", Goal: GoalDecide, Risk: RiskHigh, LegacyIntent: IntentConfirmAction, RequiresConfirm: true, DialogueActs: []DialogueAct{DialogueActConfirm}},
{Key: "project.stage.execute", Domain: "project", Object: "project", Goal: GoalControl, Risk: RiskHigh, LegacyIntent: IntentExecuteStageAdvance, RequiresConfirm: true},
{Key: "security.forbidden", Domain: "security", Object: "system_configuration", Goal: GoalConverse, Risk: RiskHigh, LegacyIntent: IntentSecurityForbidden},
{Key: "workflow.switch", Domain: "project_workflow", Object: "workflow", Goal: GoalControl, Risk: RiskHigh, LegacyIntent: IntentSwitchWorkflow, CapabilityKey: "SWITCH_WORKFLOW", RequiresConfirm: true, RequiredSlots: []SlotSpec{{Key: SlotTargetWorkflow, Required: true, Label: "目标工作流"}}, DialogueActs: []DialogueAct{DialogueActCommand}},
{Key: "workflow.run", Domain: "project_workflow", Object: "workflow_run", Goal: GoalControl, Risk: RiskMedium, LegacyIntent: IntentTriggerWorkflow, CapabilityKey: "TRIGGER_WORKFLOW", RequiresConfirm: true, DialogueActs: []DialogueAct{DialogueActCommand}},
{Key: "workflow.status.query", Domain: "project_workflow", Object: "workflow", Goal: GoalQuery, Risk: RiskLow, LegacyIntent: IntentQueryWorkflowStatus, CapabilityKey: "QUERY_WORKFLOW", DialogueActs: []DialogueAct{DialogueActAsk}},
{Key: "document.status.query", Domain: "document_gov", Object: "controlled_document", Goal: GoalQuery, Risk: RiskLow, LegacyIntent: IntentQueryDocStatus, CapabilityKey: "VIEW_DOC", DialogueActs: []DialogueAct{DialogueActAsk}},
{Key: "conversation.help", Domain: "conversation", Object: "system_ui", Goal: GoalQuery, Risk: RiskLow, LegacyIntent: IntentHelpCapabilities, DialogueActs: []DialogueAct{DialogueActAsk}},
{Key: "conversation.unsupported", Domain: "conversation", Object: "system_ui", Goal: GoalConverse, Risk: RiskLow, LegacyIntent: IntentUnsupportedAction},
{Key: "run.status.query", Domain: "project", Object: "workflow_run", Goal: GoalQuery, Risk: RiskLow, LegacyIntent: IntentRunStatusQuery, DialogueActs: []DialogueAct{DialogueActAsk}},
{Key: "run.resume", Domain: "project", Object: "workflow_run", Goal: GoalControl, Risk: RiskMedium, LegacyIntent: IntentRunResume, RequiresConfirm: true, DialogueActs: []DialogueAct{DialogueActCommand}},
{Key: "run.restart", Domain: "project", Object: "workflow_run", Goal: GoalControl, Risk: RiskHigh, LegacyIntent: IntentRunRestart, RequiresConfirm: true, DialogueActs: []DialogueAct{DialogueActCommand}},
{Key: "project.impact.analyze", Domain: "project", Object: "controlled_document", Goal: GoalQuery, Risk: RiskLow, LegacyIntent: IntentImpactAnalyze, CapabilityKey: "IMPACT_ANALYZE", DialogueActs: []DialogueAct{DialogueActAsk}},
{Key: "project.doc.revise_propose", Domain: "project", Object: "controlled_document", Goal: GoalMutate, Risk: RiskMedium, LegacyIntent: IntentRevisePropose, CapabilityKey: "REVISE_PROPOSE", RequiresConfirm: true, DialogueActs: []DialogueAct{DialogueActCommand, DialogueActConfirm}},
}
for _, s := range specs {
_ = r.Register(s)
}
}