feat: /model slash command with native Discord autocomplete#186
feat: /model slash command with native Discord autocomplete#186sh14y wants to merge 5 commits intoopenabdev:mainfrom
Conversation
…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
5494848 to
caac7a3
Compare
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.
a4290bb to
9151206
Compare
…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.
|
Native Discord slash command with autocomplete and model caching is a nice feature but touches multiple components (Discord API registration, SessionPool, autocomplete). Could you please create a Discord discussion thread and add the link to this PR description for design tracking? Thanks! 🙏 |
|
Related issues worth noting alongside this PR:
The |
…omplete - Add interaction_allowlist_ok() helper (channel, thread-parent, user checks) - Apply to handle_model_command: reject with ephemeral reply if not allowed - Apply to handle_model_autocomplete: return empty choices if not allowed Addresses review feedback from thepagent on PR openabdev#186 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
Thanks for the review! I've addressed both points:
|
Extract pure allowlist logic into ctx-free allowlist_decision() so it can be unit-tested without a Discord runtime. interaction_allowlist_ok() becomes a thin wrapper that resolves the thread parent via HTTP and delegates. Covers: empty lists, channel in/out, thread parent in/out, user in/out, and the "thread-allowed + user-denied" combination. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
Follow-up: extracted the allowlist logic into a pure
|
Design discussion: https://discord.com/channels/1491295327620169908/1491365157010542652/1493920430283686049
Summary
Adds runtime model switching via Discord's native
/modelslash command, with autocomplete-driven model selection.What changed
This PR contains three commits that build on each other:
feat: add !model command for runtime model switching via session/set_modelsession/set_modelJSON-RPC method (verified on Kiro CLI v1.29.3)models.availableModelsfromsession/newresponseauto,opus,sonnet,haiku!modelinterface (superseded in commit 3 below)fix: self-bootstrap kiro creds and config.toml inside the binaryKIRO_CRED_B64and generatesconfig.tomlfrom env vars when missing. Idempotent — no-op when files already exist.feat: replace !model text command with /model slash command + autocomplete← the main UX change!modeltext intercept entirely/modelas a guild command onready()for instant propagationinteraction_createhandler for bothCommandandAutocompleteinteractionsSessionPoolgains acached_modelssnapshot updated on everysession/new, so autocomplete can answer within Discord's 3-second deadline without spawning a fresh agent (~10s cold start)auto,opus,sonnet,haiku) appear in autocomplete as friendly shortcuts only when their target model is actually availableUX
/min Discord/modelmodelfield✅ Switched to <id>/modelwith no argumentImportant: bot invite scope
/modelwill not appear unless the bot is invited with bothbotandapplications.commandsOAuth scopes. Existing installations with onlybotscope must re-invite using a new URL — the bot account 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 --releaseclean/model(no arg) lists all available models with current marker — verified/model autoswitches and replies✅ Switched to auto— verified/model sonnetresolves alias and switchesallowlist_decision()+ 9 unit tests (empty lists, channel in/out, thread parent in/out, user in/out, combinations). Runtime smoke test deferred to post-deploy.