from __future__ import annotations from typing import Any, Literal from pydantic import BaseModel, Field from app.schemas.intent import IntentDefinition class ActionDefinition(BaseModel): action_id: str plugin_id: str risk_level: Literal["low", "medium", "high"] = "low" metadata: dict[str, Any] = Field(default_factory=dict) class DomainIntentDefinition(BaseModel): intent_id: str domain: str action_id: str | None = None plugin_id: str | None = None risk_level: Literal["low", "medium", "high"] | None = None label: str | None = None required_slots: list[str] = Field(default_factory=list) ask_templates: dict[str, str] = Field(default_factory=dict) keywords: list[str] = Field(default_factory=list) examples: list[str] = Field(default_factory=list) def to_intent_definition(self, actions: dict[str, ActionDefinition]) -> IntentDefinition: plugin_id = self.plugin_id risk_level = self.risk_level if self.action_id: action = actions[self.action_id] plugin_id = action.plugin_id if risk_level is None: risk_level = action.risk_level if not plugin_id: raise ValueError(f"intent {self.intent_id} is missing plugin_id/action_id mapping") return IntentDefinition( intent_id=self.intent_id, plugin_id=plugin_id, domain=self.domain, risk_level=risk_level or "low", required_slots=self.required_slots, ask_templates=self.ask_templates, keywords=self.keywords, examples=self.examples, ) class DomainConfig(BaseModel): intents: list[DomainIntentDefinition] = Field(default_factory=list) class ActionsConfig(BaseModel): actions: list[ActionDefinition] = Field(default_factory=list) class ResponsesConfig(BaseModel): templates: dict[str, str] = Field(default_factory=dict) class FormDefinition(BaseModel): intent_id: str required_slots: list[str] = Field(default_factory=list) ask_templates: dict[str, str] = Field(default_factory=dict) class FormsConfig(BaseModel): forms: list[FormDefinition] = Field(default_factory=list) class ConfirmationRuleConfig(BaseModel): positive_tokens: list[str] = Field(default_factory=list) negative_tokens: list[str] = Field(default_factory=list) required_intents: list[str] = Field(default_factory=list) required_risk_levels: list[Literal["low", "medium", "high"]] = Field(default_factory=list) class StopRuleConfig(BaseModel): phrases: list[str] = Field(default_factory=list) class DialogRulesConfig(BaseModel): stop: StopRuleConfig = Field(default_factory=StopRuleConfig) confirmation: ConfirmationRuleConfig = Field(default_factory=ConfirmationRuleConfig) class DialogActPatternDefinition(BaseModel): act_id: str phrases: list[str] = Field(default_factory=list) # 正则列表:文本匹配任意一个则命中该 act(用于数字类 inform) numeric_patterns: list[str] = Field(default_factory=list) class DialogActsConfig(BaseModel): acts: list[DialogActPatternDefinition] = Field(default_factory=list) # ── Context Rewrite Config ──────────────────────────────────────────────────── class ParamContextDefinition(BaseModel): """一类可相对调节参数的上下文改写规则。""" intent_ids: list[str] slot_name: str unit: str = "" step: int | float = 1 min_value: int | float = 0 max_value: int | float = 9999 default_value: int | float = 0 up_phrases: list[str] = Field(default_factory=list) down_phrases: list[str] = Field(default_factory=list) rewrite_template: str = "{value}" class ContextRewriteConfig(BaseModel): param_contexts: list[ParamContextDefinition] = Field(default_factory=list) class WorkflowTemplateStepOverride(BaseModel): depends_on: list[int] = Field(default_factory=list) condition: dict[str, Any] = Field(default_factory=dict) requires_confirmation: bool = False class WorkflowTemplateDefinition(BaseModel): template_id: str workflow_type: Literal["sequence", "conditional", "parallel"] = "sequence" intent_sequence: list[str] = Field(default_factory=list) step_overrides: list[WorkflowTemplateStepOverride] = Field(default_factory=list) trigger_keywords: list[str] = Field(default_factory=list) class WorkflowTemplatesConfig(BaseModel): templates: list[WorkflowTemplateDefinition] = Field(default_factory=list)