Skip to content

feat(assistant): wire the Nep casino guide on top of the Gemini SDK#26

Merged
netqo merged 1 commit into
devfrom
feat/assistant-nep
May 27, 2026
Merged

feat(assistant): wire the Nep casino guide on top of the Gemini SDK#26
netqo merged 1 commit into
devfrom
feat/assistant-nep

Conversation

@netqo
Copy link
Copy Markdown
Owner

@netqo netqo commented May 27, 2026

Summary

  • Replaces the Assistant placeholder with the cu-14 mockup port driven end-to-end by Google's Gemini SDK.
  • domain/assistant exposes AssistantRepository + ChatTurn + Role so the feature layer never imports the SDK. data/assistant ships the Nep system prompt and the Gemini-backed implementation; di/AssistantModule provides the singleton GenerativeModel (pinned to gemini-2.5-flash) and binds the repository.
  • feature/assistant is a sealed AssistantUiState (Welcome / Conversation) backed by a Hilt MVVM ViewModel that exposes a StateFlow. The Welcome body renders the hero + four canned suggestions; the Conversation body uses a LazyColumn with per-message UUIDs, a typing indicator, and a danger-accented bubble on failed turns. The input bar enforces the 300-char budget, sends on IME Send, and rides the soft keyboard via imePadding.
  • Promotes PulsingDot out of LoginScreenEffects into ui/components so the Nep header and the login meta row share one implementation.
  • Adds GEMINI_API_KEY to the Gradle script (read from gitignored local.properties into BuildConfig) and declares the INTERNET permission the SDK needs.

Persona + scope

NepSystemPrompt anchors the Neptunia-inspired voice (cheerful, casual, "~" suffix, refers to itself as Nep) and locks the scope to Stack Casino game rules / Provably Fair / wallet on Polygon. Off-topic asks get a polite refusal via the prompt itself instead of an extra UI state.

Notes

  • GeminiAssistantRepository logs failures under the AssistantRepo tag with full stack traces and short-circuits with a clear message when the key is empty so the UI can render a useful bubble instead of a generic exception.
  • LazyColumn keys are per-message UUIDs, not content-derived, so repeat questions inside the same minute never collide and crash the list.
  • Error bubbles are excluded from the next-turn history so a failed call never poisons the model's context window.

Test plan

  • ./gradlew assembleDebug
  • ./gradlew ktlintCheck
  • ./gradlew detekt
  • ./gradlew testDebugUnitTest (AssistantViewModelTest: 8/8 passing)
  • Installed on device, walked welcome -> suggestion -> reply, asked an off-topic question and saw the polite refusal, hit clear and confirmed the conversation resets.

Local setup

Add to stack/local.properties (gitignored):

GEMINI_API_KEY=<key from https://aistudio.google.com/apikey>

Then ./gradlew installDebug.

Replaces the Assistant placeholder with the cu-14 mockup port driven
end-to-end by Google's Gemini SDK.

  * domain/assistant: ChatTurn + Role enum + AssistantRepository
    interface so the feature layer never imports the SDK directly.
  * data/assistant: NepSystemPrompt anchors the Neptunia-inspired
    persona and the casino-only scope guardrail; GeminiAssistantRepository
    builds a fresh chat per turn, logs failures with full stack traces
    under the AssistantRepo tag, and fails fast with a clear message
    when GEMINI_API_KEY is empty so the UI can render a useful bubble
    instead of a generic exception.
  * di/AssistantModule: provides the singleton GenerativeModel pinned
    to gemini-2.5-flash (the model with the broadest free-tier coverage
    across regions) and binds the repository.
  * feature/assistant: sealed AssistantUiState (Welcome / Conversation)
    backed by an MVVM Hilt ViewModel. The welcome body renders the
    hero card and four canned suggestions; the conversation body uses
    a LazyColumn with stable per-message UUIDs so repeat questions
    inside the same minute don't crash on key collisions, plus a
    typing indicator and an error bubble accent on failed turns. The
    input bar enforces the 300-char budget, dispatches on the IME
    Send action, and rides the soft keyboard via imePadding.

Extracts the pulsing Polygon-mainnet dot out of LoginScreenEffects
into ui/components/PulsingDot so the Nep header and the login meta
row share one implementation.

Wires the Gradle script to read GEMINI_API_KEY from local.properties
(gitignored) into BuildConfig, and declares the INTERNET permission
the Gemini HTTP client needs (Firebase merges it on release builds
but a clean debug install needs it explicit, otherwise the repository
silently fails every turn).

Eight unit tests cover the ViewModel state machine: initial Welcome,
user-bubble-then-typing-then-reply, draft trimming, empty/over-budget
rejection, error bubble surface on repository failure, error filtering
from the next-turn history, multi-turn history wiring, and clear()
back to Welcome.
@netqo netqo merged commit ce3657a into dev May 27, 2026
3 checks passed
@netqo netqo deleted the feat/assistant-nep branch May 27, 2026 19:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant