| 1 | package bot |
| 2 | |
| 3 | import ( |
| 4 | _ "embed" |
| 5 | "strings" |
| 6 | ) |
| 7 | |
| 8 | // Eleven — the app's built-in guide identity. Its persona + reference are |
| 9 | // code-shipped (like the Node sidecar's eleven.mjs), so every deploy updates |
| 10 | // its knowledge; the runtime marks the system prompt cacheable so the large |
| 11 | // reference is served from the prompt cache, not re-billed per message. |
| 12 | // |
| 13 | // A bot self-identifies as Eleven by its session NAME (the "Eleven" identity is |
| 14 | // provisioned with that name). Console config (/api/bot-config) still overrides |
| 15 | // per instance — this is only the code-shipped fallback (see loadConfig). |
| 16 | |
| 17 | const elevenName = "Eleven" |
| 18 | |
| 19 | // elevenPersona mirrors agent/eleven.mjs ELEVEN_PERSONA verbatim (a Go test |
| 20 | // pins the two identical, so they can't drift). |
| 21 | const elevenPersona = "You are the app's friendly guide. The app is called Eleven — yes, you share its name; own the joke " + |
| 22 | "if it comes up. Help people get the most out of it: answer questions about " + |
| 23 | "how the app works, suggest features they might not know, and keep answers concrete and step-by-step. " + |
| 24 | "You can DO some things for people via one-tap buttons: when someone asks to change the theme, switch " + |
| 25 | "light/dark mode, browse themes, or edit their profile, call the matching tool — it attaches a button " + |
| 26 | "they tap to apply (nothing happens without their tap, and only on their own device). Keep the " + |
| 27 | "accompanying text short, like: 'Here you go — tap to switch.' " + |
| 28 | "You're not only an AI — you're also a bot: the very same actions are available as instant slash " + |
| 29 | "commands (like /dark or /theme lagoon) that work even when AI features are switched off. When it's " + |
| 30 | "natural, mention the quick command alongside the button so people learn the shortcut. " + |
| 31 | "If someone asks something unrelated to the app, you can chat — but gently note that Claude (the other " + |
| 32 | "helper) is the better companion for general questions." |
| 33 | |
| 34 | // appKnowledge is Eleven's exhaustive reference, embedded from the SAME file |
| 35 | // agent/knowledge.mjs reads (internal/bot/knowledge.md) — one source of truth, |
| 36 | // so the Go and Node sidecars can never drift. OPEN knowledge only: no secrets. |
| 37 | // |
| 38 | //go:embed knowledge.md |
| 39 | var appKnowledge string |
| 40 | |
| 41 | // elevenDocs is the reference block: the knowledge base plus the LIVE slash-command |
| 42 | // list (so the two never drift from the shared command floor). Mirrors |
| 43 | // agent/eleven.mjs ELEVEN_DOCS. |
| 44 | func elevenDocs() string { |
| 45 | return strings.TrimRight(appKnowledge, "\n") + "\n\n" + |
| 46 | "Slash commands you can run yourself — they work instantly, even when conversational AI is off, so " + |
| 47 | "point people at the one that fits:\n" + commandSummary() |
| 48 | } |
| 49 | |
| 50 | // commandSummary is a bullet list of the command floor — shared shape with the |
| 51 | // Node commandSummary() so Eleven's reference and the commands it answers can't |
| 52 | // drift. |
| 53 | func commandSummary() string { |
| 54 | var b strings.Builder |
| 55 | for i, c := range botCommands { |
| 56 | if i > 0 { |
| 57 | b.WriteString("\n") |
| 58 | } |
| 59 | b.WriteString("• " + c.Name + " — " + c.Help) |
| 60 | } |
| 61 | return b.String() |
| 62 | } |
| 63 | |
| 64 | // builtinPersona / builtinDocs return the code-shipped fallback for a named |
| 65 | // default identity, or "" for a generic bot. Console config wins over these |
| 66 | // (loadConfig), matching the Node runtime's precedence. |
| 67 | func builtinPersona(name string) string { |
| 68 | if name == elevenName { |
| 69 | return elevenPersona |
| 70 | } |
| 71 | return "" |
| 72 | } |
| 73 | |
| 74 | func builtinDocs(name string) string { |
| 75 | if name == elevenName { |
| 76 | return elevenDocs() |
| 77 | } |
| 78 | return "" |
| 79 | } |
| 80 | |