package policy import ( "ai-operator/internal/dialogue/state" "ai-operator/internal/tools" ) type Decision struct { Allowed bool ToolName string State state.ConversationState ReasonCode string UserMessageKey string RequiredNextAction string } func AuthorizeTool(session state.ConversationSession, toolName string) Decision { d := Decision{ToolName: toolName, State: session.State, ReasonCode: "ok"} if !tools.Known(toolName) { return deny(d, "unknown_tool", "denied.not_ready", "none") } if session.State == state.StateEnded { return deny(d, "call_ended", "closing.started", "none") } if toolName == tools.SearchKnowledgeBase { return authorizeSearch(session, d) } allowed := allowedByState(session.State, toolName) if !allowed { return deny(d, "tool_not_allowed_in_state", "denied.not_ready", nextAction(session)) } d.Allowed = true return d } func authorizeSearch(session state.ConversationSession, d Decision) Decision { if session.State == state.StateEnded || session.State == state.StateClosing || session.State == state.StateHandoff { return deny(d, "state_not_ready", "denied.not_ready", nextAction(session)) } d.Allowed = true return d } func allowedByState(s state.ConversationState, tool string) bool { switch s { case state.StateLanguageSelection: return tool == tools.SearchKnowledgeBase || tool == tools.SetLanguage || tool == tools.SetRegion || tool == tools.RequestHumanHandoff || tool == tools.EndCall case state.StateRegionSelection: return tool == tools.SearchKnowledgeBase || tool == tools.SetRegion || tool == tools.SetLanguage || tool == tools.RequestHumanHandoff || tool == tools.EndCall case state.StateReadyToHelp: return tool == tools.SearchKnowledgeBase || tool == tools.SetLanguage || tool == tools.SetRegion || tool == tools.RequestHumanHandoff || tool == tools.EndCall case state.StateQuestionAnswering: return tool == tools.SearchKnowledgeBase || tool == tools.SetLanguage || tool == tools.SetRegion || tool == tools.RequestHumanHandoff || tool == tools.EndCall case state.StateHandoff: return tool == tools.RequestHumanHandoff || tool == tools.EndCall case state.StateClosing: return tool == tools.EndCall default: return false } } func deny(d Decision, reason, key, action string) Decision { d.Allowed = false d.ReasonCode = reason d.UserMessageKey = key d.RequiredNextAction = action return d } func nextAction(session state.ConversationSession) string { if session.Language != state.LanguageRU && session.Language != state.LanguageKK { return "infer_language" } if session.Region.Status != state.RegionSelected || session.Region.Code == "" { return "use_global_or_ask_region_if_needed" } return "wait_for_question" }