// Package intent 提供通用的意图识别机制:意图定义(spec)、注册表与配置合并、 // 四级漏斗识别器(guard → expectation → rules → adjudicate)、槽位抽取与诊断。 // // 本包不含任何业务意图内容;词表、正则与守卫规则一律由宿主以 Go 注册或 JSON 配置提供。 // 识别路径纯内存、确定性:同输入 + 同快照 → 同结果。「无匹配」(fallback)是正常 // 识别结果而非错误;错误只表示系统级失败(配置损坏、调用方参数不合法)。 package intent import ( "fmt" "sort" "strings" ) // 规范码常量。字符串值与 Error-Code-System 的 intent 域 / sys 域种子码一致, // 由 catalogcheck 包的对齐测试防止两处漂移。 const ( // InvalidSpec 表示意图定义或配置校验失败:id 冲突、正则不合法、未知字段、 // matcher 缺少正向条件、槽位 group 越界、覆盖版本未递增等。整批加载已原子拒绝。 InvalidSpec = "intent.invalid_spec" // SpecProtected 表示 overlay 试图覆盖或禁用保护域内的 spec。保护域由宿主构建时声明。 SpecProtected = "intent.spec_protected" // LoadFailed 表示配置读取或解析失败。失败时保留上一生效快照。 LoadFailed = "intent.load_failed" // InvalidArgument 复用框架域,表示调用方错误:nil 快照、输入超长。 InvalidArgument = "sys.invalid_argument" ) // Error 是本模块的系统级错误。实现 ErrorCode / ErrorFields 鸭子方法, // logging-system 的 logsys 识别后自动把码写入 code、字段并入 fields,无需互相依赖。 type Error struct { Code string Message string Fields map[string]any } // Error 实现error接口。 func (e *Error) Error() string { var b strings.Builder b.WriteString("intent: ") b.WriteString(e.Code) b.WriteString(": ") b.WriteString(e.Message) keys := make([]string, 0, len(e.Fields)) for k := range e.Fields { keys = append(keys, k) } sort.Strings(keys) for _, k := range keys { fmt.Fprintf(&b, " %s=%v", k, e.Fields[k]) } return b.String() } // ErrorCode 返回规范码,供日志与错误信封对齐。 func (e *Error) ErrorCode() string { return e.Code } // ErrorFields 返回结构化定位字段(spec id、来源文件、字段路径等)。 func (e *Error) ErrorFields() map[string]any { return e.Fields } func newError(code, message string, kv ...any) *Error { return &Error{Code: code, Message: message, Fields: fieldsFrom(kv)} } func (e *Error) with(kv ...any) *Error { merged := make(map[string]any, len(e.Fields)+len(kv)/2) for k, v := range e.Fields { merged[k] = v } for i := 0; i+1 < len(kv); i += 2 { if k, ok := kv[i].(string); ok { merged[k] = kv[i+1] } } return &Error{Code: e.Code, Message: e.Message, Fields: merged} } func fieldsFrom(kv []any) map[string]any { m := make(map[string]any, len(kv)/2) for i := 0; i+1 < len(kv); i += 2 { if k, ok := kv[i].(string); ok { m[k] = kv[i+1] } } return m }