// Package enums is the single Go-side source of truth for the shared client // enumerations published at GET /api/v1/meta/enums (Android collaboration B4, // design/07 §6). It carries three tables — platform (a message's source // platform), mood (a persona's emotion) and mode (the presentation mode a // message was produced in) — so every client maps ids to labels from the same // place instead of hardcoding its own, which is what made source badges and mood // labels drift per client. // // Adding a value is a non-breaking contract change. A value absent from a table // must be rendered raw by the client — never dropped, never an error — and that // policy is published alongside the tables (UnknownFallback). The anti-drift // tests in this package pin each table to its real source of truth: the platform // table to the built-in adapters' Name() values plus the Web main-session source // (internal/runtime/history), the mood table to internal/persona/emotion's // built-in states, and the mode table to the nine modes design/07 §1 defines // (mirrored by frontend/web/src/lib/types.ts MODES). package enums // Item is one enumeration entry: the machine-readable ID a client compares // against, plus the default Simplified-Chinese label it may display directly. // The label is a default, not a contract: a client with i18n may override it. type Item struct { ID string `json:"id"` Label string `json:"label"` } // UnknownFallback is the machine-readable fallback policy a client applies to a // value that is not in the published tables: display the value exactly as // received — no label substitution, no drop, no error. It is served in the same // response as the tables so a client reads the policy and the data together. const UnknownFallback = "display-raw" // Platforms returns the authoritative message-source platforms: the Web main // session plus every built-in IM adapter, keyed by the adapter's Name() value // (kook, qq-obv11, weixin-ilink, telegram, webhook). // // Each call builds a fresh slice, so a caller may sort or otherwise mutate its // copy without affecting another — the table itself is never package-level // mutable state. func Platforms() []Item { return []Item{ {ID: "web", Label: "网页"}, {ID: "kook", Label: "KOOK"}, {ID: "qq-obv11", Label: "QQ"}, {ID: "weixin-ilink", Label: "微信"}, {ID: "telegram", Label: "Telegram"}, {ID: "webhook", Label: "Webhook"}, } } // Moods returns the authoritative persona-emotion values, mirroring // internal/persona/emotion's built-in states (calm/happy/excited/sad/angry). The // emotion state machine is extensible — a persona may register further states via // AddTransition — so a client must treat an unlisted mood as display-raw rather // than assuming this table is closed. func Moods() []Item { return []Item{ {ID: "calm", Label: "平静"}, {ID: "happy", Label: "开心"}, {ID: "excited", Label: "兴奋"}, {ID: "sad", Label: "低落"}, {ID: "angry", Label: "生气"}, } } // Modes returns the authoritative behavior/presentation modes (design/01 §3, // design/07 §1). A mode drives how a message is rendered, never what the persona // is able to do: it is a presentation dimension, not a capability boundary. func Modes() []Item { return []Item{ {ID: "chat", Label: "对话"}, {ID: "code", Label: "代码"}, {ID: "home", Label: "家居"}, {ID: "work", Label: "工作"}, {ID: "docs", Label: "文档"}, {ID: "voice", Label: "语音"}, {ID: "vision", Label: "视觉"}, {ID: "agents", Label: "智能体"}, {ID: "settings", Label: "设置"}, } }