ARIA Dialogue¶
Status: ๐ง Partial โ ARIA chat is reachable, sanitized, and per-player-isolated, but its replies are deterministic intent-templates with NO LLM call โ the documented provider chain is wired but carries no production traffic (matches the "Deep Brain" framing per ADR-0092 ยง3, folded into
OPERATIONS/aria.mdยง2 today). Re-verified 2026-08-04: encrypted-memory writes confirmed live (aria_personal_intelligence_service.py_encrypt_memory, called from both memory-creation paths). No further divergence found. ADR-0093 item 28 greenlit the "dark trio" โ LLM-scored narrative haggling with a server-side clamp (see../FEATURES/economy/haggling.md, still ๐ design-only pending build), tool-first Deep-Brain retrieval overaria_data_streams-scoped read-only tools, and true-spend cost metering against the ADR-0057 caps (metering to be built first, as the safety piece) โ all three remain dark behindARIA_LLM_CHAT_ENABLED/ARIA_PROMPT_CLASSIFIER_ENABLEDper the item-17 standing order, authorization only, not yet shipped (folded from ADR-0093, re-verified 2026-08-07).
Purpose¶
ARIA is the per-player AI assistant. The dialogue system is the pipeline that turns a player message into a sanitized, language-aware, context-rich prompt; routes it through a fallback-equipped multi-provider stack; sanitizes the response; logs the exchange; and pushes the assistant reply back over the realtime bus. As shipped today (per the Status banner above and DECISIONS.md's aria-llm-vs-template entry, confirming this as the intended-for-now architecture, not a stopgap), the "stack" resolves to deterministic intent-templates โ the LLM provider slots (AI_PROVIDER_PRIMARY / _SECONDARY / _FALLBACK below) are wired end-to-end but carry no production traffic. Every step is auditable; every step has a deterministic fallback so the assistant is never fully unavailable.
Inputs¶
The pipeline reads:
- The raw player message body.
- The player's User/Player row (locale, aria_consciousness_level, aria_relationship_score, blocked status).
- The player's ARIAPersonalMemory, ARIAExplorationMap, ARIAMarketIntelligence, and recent ARIATradingObservation rows (top-K by recency or aggregate-relevance).
- Current session context: sector, ship, recent dialogue exchanges (last N turns).
- AI provider config (env): AI_PROVIDER_PRIMARY, AI_PROVIDER_SECONDARY, AI_PROVIDER_FALLBACK.
- Security config: rate limits, max chars, cost cap, blocked patterns.
The system fires on:
- POST /api/v1/ai/chat โ direct chat send.
- POST /api/v1/ai/recommendations โ request a recommendation (system-style query).
- WebSocket aria:send command on the realtime bus. [NO-CANON naming discrepancy, flagged 2026-08-06, doc-only โ no code changed]: the actual live websocket contract (services/gameserver/src/services/enhanced_websocket_service.py:693-762) dispatches on message-type-level ai_request (trading recommendations / market predictions, _handle_ai_request) and aria_chat (conversational ARIA, _handle_aria_chat) โ not a literal aria:send command name. Both share an independent rate-limit bucket, max_ai_requests_per_minute (default 60/min, distinct from the REST POST /api/v1/ai/chat limits above), keyed on any message_type starting ai_ or equal to aria_chat. Whether aria:send is a stale/renamed reference or a separate legacy transport wasn't determined by this pass โ flagged for someone with fuller websocket-contract context rather than guessed at, since this is AI-dialogue-adjacent.
- First-login dialogue (specialized variant โ see first-login.md).
- Tool-result callbacks (when the model invokes a tool and the tool returns).
Process¶
Player message
โ
โผ
[1] Client-side sanitize (DOMPurify, length cap)
โ Server-side: build dialogue context with auth_snapshot
โ โข subscription_tier (User.subscription_tier at this instant)
โ โข aria_consciousness_level (Player.aria_consciousness_level)
โ โข aria_bonus_multiplier (Player.aria_bonus_multiplier)
โ Per ADR-0058 A-F1, all subsequent steps read these from the
โ snapshot, never from the live row. A subscription upgrade or
โ consciousness level-up landing mid-exchange takes effect on
โ the NEXT exchange โ the in-flight one completes consistently.
โ
โผ
[2] Server input gate (ai_security_service)
โ โข length / word cap
โ โข injection patterns (script, sql, dunder, eval)
โ โข prompt-injection patterns (25+ regexes)
โ โข jailbreak patterns (โฅ2 indicators)
โ โข token-burning (>30% repetition)
โ โข classifier category policy: instruction_override / extraction /
โ jailbreak / role_confusion โ hard block (400, lore-friendly
โ rejection); off-topic / clean โ filtered + logged + trust-laddered
โ โข rate limit (req/min, /day โ per-hour retired per AU2-18)
โ โข cost cap (USD/day, USD/request)
โ โ on hit: log SecurityViolation, penalize trust, possibly block
โ
โผ
[3] Intent classification
โ โข lightweight classifier (rule + small model)
โ โข routes: chat | trade-advice | combat-advice | explore | market-query
โ | colony-advice | meta (memory recall)
โ
โผ
[4] Multilingual context build (multilingual_ai_service)
โ โข translation_service.get_user_language_preference(user_id)
โ โข cultural-context tag (western/hispanic/chinese/...)
โ โข cultural guidelines (tone, formality, humor, authority)
โ โ response_language fixed; instruction-stream tagged
โ
โผ
[5] Prompt assembly
โ โข system header (role, persona, language directive)
โ โข personal memory snippets (top-K, decay-weighted)
โ โข exploration data slice (sectors visited, ports known)
โ โข market intelligence slice (relevant commodities)
โ โข last N dialogue turns
โ โข the (sanitized) player message embedded in a JSON envelope
โ so injected text lands inside a data field, not the
โ instruction stream
โ โข tool definitions (market_lookup, sector_info, route_plan, ...)
โ
โผ
[6] Provider chain (ai_provider_service)
โ primary โ secondary โ manual fallback
โ each step has a hard timeout; chain advances on failure or 5xx
โ
โผ
[7] Tool invocation loop
โ while response.tool_call:
โ โข validate tool args (schema)
โ โข run tool (read-only handler โ market query, sector lookup, ...)
โ โข feed result back as a follow-up turn
โ โข cap at 3 tool turns to avoid infinite loops
โ
โผ
[8] Response sanitize
โ โข strip control characters
โ โข cap length
โ โข run output filters (no PII echo, no other-player private data)
โ โข DOMPurify on the client before render
โ
โผ
[9] Persist
โ โข ARIAPersonalMemory row (encrypted) for the exchange
โ โข DialogueExchange row in chat history
โ โข ARIASecurityLog if any anomaly
โ โข increment Player.aria_total_interactions
โ โข check consciousness threshold (50/150/400/1000) and bump
โ aria_consciousness_level + aria_bonus_multiplier
โ
โ Multiplier semantics (per ADR-0057 A-D2): the multiplier applies
โ CONTINUOUSLY on every ARIA interaction โ read on each call to
โ scale recommendation strength, narration richness, observation
โ depth. Level transitions are atomic boundary events; the
โ multiplier itself is not gated to those transitions.
โ
โผ
[10] Push (realtime-bus)
โ โข aria_message event (personal:{user_id})
โ โข turn_pool_updated if multiplier changed
Provider chain detail¶
AI_PROVIDER_PRIMARY=openai
AI_PROVIDER_SECONDARY=anthropic
AI_PROVIDER_FALLBACK=manual # rule-based, always available
Each provider exposes a uniform analyze(...) / generate(...) API. Selection is per-request; a provider failure (timeout, 5xx, content filter) advances the chain. The manual provider (enhanced_manual_provider.py) replicates the response shape with rule-based pattern matching so the assistant is never offline.
Rate / cost controls¶
requests_per_minute = 10 (env: ARIA_RPM) # anti-burst cap
requests_per_day = 500 (env: ARIA_RPD) # long-term ceiling
max_cost_per_day_usd = 2.00 (env: ARIA_DAILY_USD) # per-player daily spend cap
max_cost_per_request = 0.25 (env: ARIA_REQ_USD) # per-request hard ceiling
max_chars_per_request = 500
max_words_per_request = 100
Plus a per-instance circuit breaker: instance_max_cost_per_day_usd = 50.00 (env: ARIA_INSTANCE_DAILY_USD) โ defense-in-depth backstop on aggregate spend across all players. Per-hour cap retired (AU2-18) โ was dominated by per-minute math. When daily spend hits 80% of the per-player limit, the player is blocked for the rest of the UTC day with ERR_DAILY_BUDGET_EXHAUSTED.
Trust scoring¶
Each player starts with trust = 1.0. Penalties:
- Injection attempt: โ0.3
- Prompt injection: โ0.2
- Jailbreak: โ0.4
- System command: โ0.5
- Rate-limit hit: โ0.1
Severe violations auto-block for 24 h (progressive: 1 h โ 6 h โ 24 h on repeats).
Multilingual routing¶
The user's language preference (User.locale) drives:
- Response language directive in the prompt.
- Cultural guideline injection (tone, formality, humor, authority).
- Pre-translated UI strings used in tool outputs (see translation_service).
Fallback to en if the user has no preference or the preference is unsupported.
Outputs / state changes¶
Per dialogue turn:
- ARIAPersonalMemory โ encrypted memory entry (importance score, content hash for dedup).
- DialogueExchange (or equivalent) โ chat-history row.
- ARIASecurityLog โ if any security event fired.
- Player.aria_total_interactions โ incremented.
- Player.aria_consciousness_level, Player.aria_bonus_multiplier โ bumped on threshold crossings.
- User.trust_score โ adjusted per any violation.
Events emitted:
- aria_message โ personal unicast with the assistant's reply.
- turn_pool_updated โ if multiplier changed (downstream of consciousness bump).
- aria_security_alert โ admin feed, on dangerous violations.
- notification โ personal, if a tool surfaced an alert (e.g. price hit).
Downstream: - Memory writes feed future ARIA queries (recall in step 5). - Security log feeds the admin dashboard.
Invariants¶
- Every player input is rate-limited and sanitized before reaching any provider.
- The player's input is never inlined directly into the instruction stream โ it lives in a JSON data field.
- Each ARIA instance is per-player; no cross-player data is read or written.
- Memories are encrypted at rest (Fernet/AES-256) under
ARIA_ENCRYPTION_KEY, a persistent stack-loaded secret (same discipline asJWT_SECRET) โ memories survive gameserver restarts. - Provider failure never produces an unhandled exception to the user โ the chain falls through to manual fallback.
- Tool-call loops cap at 3 iterations; runaway prevented.
- Cost caps are enforced before the provider call, not after.
- Audit trail (
ARIASecurityLog) is written for every detected violation and every blocked request. - Output is sanitized on both server and client (defense in depth: server strip + client DOMPurify).
Failure modes¶
| Mode | Target handling |
|---|---|
| All providers down | Manual fallback delivers a rule-based response; user sees a degraded-mode banner. |
| Provider returns malformed JSON | Validator catches; chain advances; fallback if exhausted. |
| Tool call to unknown tool | Reject with explicit error; do not advance chain (model bug, not provider failure). |
| Player rate-limited | Return 429; suggest cooldown; emit aria_rate_limited. |
| Cost cap reached | Block until next UTC day; admin can lift via security action. |
| Injection / jailbreak / extraction / role_confusion / instruction_override | Hard block (400), log, penalize trust; reply with a lore-friendly in-voice rejection, not a raw error string. The four-category block set (instruction_override / extraction / jailbreak / role_confusion) was ratified as the layer-4 policy by ADR-0093 item 14 โ every other classification flows filtered + logged + trust-laddered rather than blocked (folded from ADR-0093, re-verified 2026-08-07). |
| Translation lookup fails | Fall back to English directive; log the locale that missed. |
| Memory decryption fails (key rotation, corruption) | Skip that memory snippet; continue with reduced context; log. |
| Realtime bus push fails | Reply still persisted; client picks up via REST history on next open. |
| First-login variant during normal chat (mistaken context) | First-login flow is a separate handler (see first-login.md); cross-routing rejected at intent classification. |
Source map¶
| Concern | Path (target) |
|---|---|
| Dialogue orchestration | services/gameserver/src/services/ai_dialogue_service.py |
| Multi-provider client | services/gameserver/src/services/ai_provider_service.py |
| Manual fallback provider | services/gameserver/src/services/enhanced_manual_provider.py |
| Multilingual routing | services/gameserver/src/services/multilingual_ai_service.py |
| Translation lookups | services/gameserver/src/services/translation_service.py |
| Personal memory + tool data | services/gameserver/src/services/aria_personal_intelligence_service.py |
| Trade-DNA / market intelligence | services/gameserver/src/services/ai_trading_service.py |
| Security gate | services/gameserver/src/services/ai_security_service.py |
| Audit log model | services/gameserver/src/models/aria_personal_intelligence.py:ARIASecurityLog |
| Encrypted memory model | services/gameserver/src/models/aria_personal_intelligence.py:ARIAPersonalMemory |
| Chat / recommendation routes | services/gameserver/src/api/routes/ai.py, enhanced_ai.py |
| Admin security routes | services/gameserver/src/api/routes/admin_comprehensive.py |
| Player-client UI | services/player-client/src/components/ai/EnhancedAIAssistant.tsx |
Related¶
- DATA_MODELS: ARIA tables in
../DATA_MODELS/player.md. - FEATURES:
../FEATURES/economy/trading.md(market intelligence consumer). - OPERATIONS:
../OPERATIONS/aria.md,../OPERATIONS/i18n.md. - SYSTEMS: first-login.md, realtime-bus.md, turn-regeneration.md, market-pricing.md.
- API:
POST /api/v1/ai/chat,POST /api/v1/ai/recommendations.