Skip to content

feat: /model slash command with native Discord autocomplete#192

Closed
sh14y wants to merge 3 commits intoopenabdev:mainfrom
sh14y:feat/model-slash-command
Closed

feat: /model slash command with native Discord autocomplete#192
sh14y wants to merge 3 commits intoopenabdev:mainfrom
sh14y:feat/model-slash-command

Conversation

@sh14y
Copy link
Copy Markdown

@sh14y sh14y commented Apr 11, 2026

Summary

Replaces the text-based !model command (#186) with a Discord-native /model slash command that supports autocomplete and arrow-key model selection.

Depends on #186 — this branch is stacked on feat/model-switch-command (which adds the underlying session/set_model ACP plumbing). Please review and merge #186 first.

What changed

  • SessionPool cached_models — every session/new now updates a global snapshot of available models on the pool, so autocomplete can serve suggestions instantly without spawning a fresh agent (~10s cold start would blow Discord's 3s autocomplete deadline).
  • Startup warmupmain.rs spawns a background __warmup__ session at boot so the cache is populated before the first slash command fires.
  • /model registration — registered as a guild command on ready() for every guild the bot is in. Guild commands appear instantly; global commands take up to 1 hour to propagate.
  • interaction_create handler — dispatches Command (the actual /model invocation) and Autocomplete (live filtering as the user types) interactions. The set path defers the response since cold session creation may exceed 3s.
  • Aliases in autocompleteauto, opus, sonnet, haiku are surfaced as friendly shortcuts (sonnet → claude-sonnet-4.6) but only when their target is actually available.
  • !model removed/model is the replacement, not an addition. The text-command intercept in discord.rs is gone.
  • README — documents the applications.commands OAuth scope requirement and the new /model UX.

UX

Action Result
Type /m in Discord Native command picker shows /model
Tab into the model field Autocomplete returns aliases + all available model ids (current model marked)
Pick with ↑↓, hit enter Bot defers, sets the model on the channel/thread session, replies ✅ Switched to <id>
/model with no argument Bot replies with the full list and marks the current selection

Important: bot invite scope

/model will not appear unless the bot is invited with both bot and applications.commands OAuth scopes. Existing installations that only have bot scope will need to re-invite the bot using a new URL — the bot account itself stays the same and no data is lost.

The README has been updated to call this out in the Quick Start section.

Test plan

  • cargo build --release clean
  • Verify /model (no arg) lists all available models with current marker
  • Verify /model auto switches and replies ✅ Switched to auto
  • Verify /model sonnet resolves alias and switches
  • Verify autocomplete shows live filtered suggestions as you type
  • Verify the warmup task populates the model cache before first use
  • Verify allowlist (channel + user) is enforced for the slash command path

sh14y added 3 commits April 10, 2026 22:25
…model

- Add ModelInfo struct and model state fields to AcpConnection
- Parse available models from session/new response
- Add session_set_model() and resolve_model_alias() methods
- Add !model Discord command to list and switch models
- Support aliases: opus, sonnet, haiku, auto

Kiro ACP session/set_model verified on Kiro CLI v1.29.3
Move the entrypoint.sh logic into main.rs so openab is independent of any
external shell wrapper. Before loading config, it now:

  1. Restores ~/.local/share/kiro-cli/data.sqlite3 from KIRO_CRED_B64 if
     missing (idempotent — skips when file already exists, e.g. from a
     mounted volume).
  2. Generates the config file from DISCORD_BOT_TOKEN / DISCORD_CHANNEL_ID
     env vars when the path doesn't exist. Secrets are written as literal
     ${VAR} placeholders so they get expanded by load_config() at read
     time and never land on disk in plaintext.

Why: Zeabur deployments were intermittently running images built without
the entrypoint shim (e.g. when the source branch was switched mid-flight),
producing "failed to read /etc/openab/config.toml" with no entrypoint logs.
With the bootstrap inside the binary, the deploy is robust to any image
build path that happens to omit our shell wrapper.

The Dockerfile entrypoint.sh remains as a belt-and-suspenders no-op when
present.
…plete

Discord's slash commands give a much better UX than text commands:
- Typing /m surfaces /model in Discord's native command picker
- Autocomplete on the model option shows the live list of available
  models (and aliases) with arrow-key selection
- Discord renders the response as an interaction reply instead of
  cluttering the channel as a regular bot message

Implementation notes:

- SessionPool gains a cached_models snapshot updated on every
  session_new(). Autocomplete must respond within Discord's 3-second
  deadline, which rules out spawning a fresh kiro-cli (~10s cold start).
- main.rs adds a background warmup task that creates one session at
  startup so the cache is populated before the first user invocation.
- /model is registered as a guild command on ready() for instant
  propagation (global commands take up to 1 hour).
- The interaction handler defers the response on the set path because
  cold session creation can exceed Discord's 3s window for non-deferred
  replies.
- README documents the applications.commands scope requirement; without
  it the slash command will not appear in Discord clients.

The !model text command is removed entirely — /model is its replacement,
not an addition.
@sh14y sh14y requested a review from thepagent as a code owner April 11, 2026 01:59
@sh14y
Copy link
Copy Markdown
Author

sh14y commented Apr 11, 2026

Superseded by #186 — fast-forwarded the slash command commit onto feat/model-switch-command because our deployment target is locked to that branch. PR #186 now contains the full feature stack (ACP plumbing + slash command UI). Closing this duplicate.

@sh14y sh14y closed this Apr 11, 2026
@sh14y sh14y deleted the feat/model-slash-command branch April 11, 2026 02:31
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