(host: SlashCommandHost, input: string)
| 169 | } |
| 170 | |
| 171 | async function executeSlashCommand(host: SlashCommandHost, input: string): Promise<void> { |
| 172 | const parsedCommand = parseSlashInput(input); |
| 173 | const intent = resolveSlashCommandInput({ |
| 174 | input, |
| 175 | skillCommandMap: host.skillCommandMap, |
| 176 | pluginCommandMap: host.pluginCommandMap, |
| 177 | isStreaming: host.state.appState.streamingPhase !== 'idle', |
| 178 | isCompacting: host.state.appState.isCompacting, |
| 179 | }); |
| 180 | |
| 181 | switch (intent.kind) { |
| 182 | case 'not-command': |
| 183 | return; |
| 184 | case 'blocked': |
| 185 | host.track('input_command_invalid', { reason: 'blocked', command: intent.commandName }); |
| 186 | host.showError(slashBusyMessage(intent.commandName, intent.reason)); |
| 187 | return; |
| 188 | case 'invalid': |
| 189 | host.track('input_command_invalid', { |
| 190 | reason: intent.reason, |
| 191 | command: intent.commandName, |
| 192 | }); |
| 193 | host.showError(`Invalid slash command: /${intent.commandName}`); |
| 194 | return; |
| 195 | case 'skill': { |
| 196 | const session = host.session; |
| 197 | if (host.state.appState.model.trim().length === 0 || session === undefined) { |
| 198 | host.showError(LLM_NOT_SET_MESSAGE); |
| 199 | return; |
| 200 | } |
| 201 | host.track('input_command', { |
| 202 | command: intent.commandName, |
| 203 | skill_name: intent.skillName, |
| 204 | }); |
| 205 | host.sendSkillActivation(session, intent.skillName, intent.args); |
| 206 | return; |
| 207 | } |
| 208 | case 'plugin-command': { |
| 209 | if (host.state.appState.model.trim().length === 0) { |
| 210 | host.showError(LLM_NOT_SET_MESSAGE); |
| 211 | return; |
| 212 | } |
| 213 | const session = host.session; |
| 214 | if (session === undefined) { |
| 215 | host.showError(LLM_NOT_SET_MESSAGE); |
| 216 | return; |
| 217 | } |
| 218 | host.track('input_command', { command: `${intent.pluginId}:${intent.commandName}` }); |
| 219 | host.activatePluginCommand(session, intent.pluginId, intent.commandName, intent.args); |
| 220 | return; |
| 221 | } |
| 222 | case 'message': |
| 223 | // Unknown slash command: let /dance claim it before it falls through to |
| 224 | // the model as a normal message. This runs *after* builtin and skill |
| 225 | // resolution, so a real command or a same-named skill always wins. |
| 226 | if (parsedCommand !== null && tryHandleDanceCommand(host, parsedCommand)) { |
| 227 | return; |
| 228 | } |
no test coverage detected