Summary
Add a !model Discord command that lets users list and switch the underlying LLM model for the current ACP session at runtime, without restarting the bot or recreating the session.
Motivation
Kiro CLI's ACP server already exposes multiple models (Claude Opus 4.6 / Sonnet 4.6 / Haiku 4.5 / Auto). Today openab pins whatever Kiro chose at session/new time and there is no in-Discord way to change it. Different tasks benefit from different models (e.g. Opus for hard reasoning, Haiku for cheap quick replies, Auto when you don't care). Letting users switch in-thread keeps the workflow inside Discord.
ACP protocol verification
Verified against Kiro CLI v1.29.3:
session/new response now includes a models object:
{
"result": {
"sessionId": "...",
"models": {
"currentModelId": "auto",
"availableModels": [
{ "modelId": "auto", "name": "Auto", "description": "..." },
{ "modelId": "claude-opus-4.6", "name": "Opus 4.6", "description": "..." },
{ "modelId": "claude-sonnet-4.6", "name": "Sonnet 4.6","description": "..." },
{ "modelId": "claude-haiku-4.5", "name": "Haiku 4.5", "description": "..." }
]
}
}
}
session/set_model JSON-RPC method accepted:
{ "method": "session/set_model",
"params": { "sessionId": "...", "modelId": "claude-opus-4.6" } }
→ { "result": {} }
Proposed command design
Inside an allowed channel/thread:
| Input |
Behavior |
!model |
List all available models, marking the current one |
!model opus |
Switch to claude-opus-4.6 |
!model sonnet |
Switch to claude-sonnet-4.6 |
!model haiku |
Switch to claude-haiku-4.5 |
!model auto |
Switch back to auto-routing |
!model <id> |
Accept any exact modelId from availableModels |
!model <unknown> |
Reply with error + available list |
Aliases (opus, sonnet, haiku, auto) are resolved client-side; otherwise the exact modelId is forwarded.
Models marked [Deprecated] or [Internal] in their description are filtered out of the list.
Implementation outline
- New
ModelInfo { model_id, name, description } in src/acp/connection.rs
AcpConnection gains current_model: String and available_models: Vec<ModelInfo>
session_new() parses the models block from the response
- New
AcpConnection::session_set_model(model_id) and resolve_model_alias(input)
Handler::message() intercepts messages whose prompt starts with !model and dispatches via pool.with_connection
Backend scope
This is currently wired against the Kiro ACP backend (which is the only one I've validated session/set_model on). Other backends that don't implement the method will simply error on switch and report _(no models reported by agent — backend may not support model switching)_ when listing.
PR with the implementation will follow this issue.
Summary
Add a
!modelDiscord command that lets users list and switch the underlying LLM model for the current ACP session at runtime, without restarting the bot or recreating the session.Motivation
Kiro CLI's ACP server already exposes multiple models (Claude Opus 4.6 / Sonnet 4.6 / Haiku 4.5 / Auto). Today openab pins whatever Kiro chose at
session/newtime and there is no in-Discord way to change it. Different tasks benefit from different models (e.g. Opus for hard reasoning, Haiku for cheap quick replies, Auto when you don't care). Letting users switch in-thread keeps the workflow inside Discord.ACP protocol verification
Verified against Kiro CLI v1.29.3:
session/newresponse now includes amodelsobject:{ "result": { "sessionId": "...", "models": { "currentModelId": "auto", "availableModels": [ { "modelId": "auto", "name": "Auto", "description": "..." }, { "modelId": "claude-opus-4.6", "name": "Opus 4.6", "description": "..." }, { "modelId": "claude-sonnet-4.6", "name": "Sonnet 4.6","description": "..." }, { "modelId": "claude-haiku-4.5", "name": "Haiku 4.5", "description": "..." } ] } } }session/set_modelJSON-RPC method accepted:{ "method": "session/set_model", "params": { "sessionId": "...", "modelId": "claude-opus-4.6" } } → { "result": {} }Proposed command design
Inside an allowed channel/thread:
!model!model opusclaude-opus-4.6!model sonnetclaude-sonnet-4.6!model haikuclaude-haiku-4.5!model auto!model <id>modelIdfromavailableModels!model <unknown>Aliases (
opus,sonnet,haiku,auto) are resolved client-side; otherwise the exactmodelIdis forwarded.Models marked
[Deprecated]or[Internal]in their description are filtered out of the list.Implementation outline
ModelInfo { model_id, name, description }insrc/acp/connection.rsAcpConnectiongainscurrent_model: Stringandavailable_models: Vec<ModelInfo>session_new()parses themodelsblock from the responseAcpConnection::session_set_model(model_id)andresolve_model_alias(input)Handler::message()intercepts messages whose prompt starts with!modeland dispatches viapool.with_connectionBackend scope
This is currently wired against the Kiro ACP backend (which is the only one I've validated
session/set_modelon). Other backends that don't implement the method will simply error on switch and report_(no models reported by agent — backend may not support model switching)_when listing.PR with the implementation will follow this issue.