or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

client.mdcommands.mdcomponents.mddiscord-models.mdevents.mdextensions.mdindex.md

commands.mddocs/

0

# Commands & Interactions

1

2

Create slash commands, context menus, and handle all interaction types with modern Discord bot functionality.

3

4

## Slash Commands

5

6

### Basic Slash Command

7

8

```python

9

from interactions import slash_command, SlashContext

10

11

@slash_command(name="hello", description="Say hello to someone!")

12

async def hello_command(ctx: SlashContext):

13

await ctx.send("Hello World!")

14

```

15

16

### Slash Command with Options

17

18

```python

19

from interactions import slash_command, slash_option, SlashContext, OptionType

20

21

@slash_command(name="greet", description="Greet a user")

22

@slash_option(

23

name="user",

24

description="User to greet",

25

required=True,

26

opt_type=OptionType.USER

27

)

28

@slash_option(

29

name="message",

30

description="Custom message",

31

required=False,

32

opt_type=OptionType.STRING

33

)

34

async def greet_command(ctx: SlashContext, user: Member, message: str = "Hello"):

35

await ctx.send(f"{message}, {user.mention}!")

36

```

37

38

### Type-Specific Option Decorators

39

40

```python

41

from interactions import (

42

slash_command, slash_str_option, slash_int_option,

43

slash_bool_option, slash_user_option, slash_channel_option,

44

slash_role_option, slash_mentionable_option, slash_attachment_option,

45

slash_float_option, SlashContext

46

)

47

48

@slash_command(name="complex", description="Complex command with multiple option types")

49

@slash_str_option(name="text", description="Text input", required=True, max_length=100)

50

@slash_int_option(name="number", description="Number input", min_value=1, max_value=100)

51

@slash_bool_option(name="flag", description="Boolean flag")

52

@slash_user_option(name="target", description="Target user")

53

@slash_channel_option(name="destination", description="Target channel")

54

@slash_role_option(name="role", description="Role to assign")

55

@slash_attachment_option(name="file", description="File to process")

56

@slash_float_option(name="rating", description="Rating", min_value=0.0, max_value=5.0)

57

async def complex_command(

58

ctx: SlashContext,

59

text: str,

60

number: int = 50,

61

flag: bool = False,

62

target: Member = None,

63

destination: GuildChannel = None,

64

role: Role = None,

65

file: Attachment = None,

66

rating: float = 0.0

67

):

68

await ctx.send(f"Processing: {text} with number {number}")

69

```

70

71

### Slash Command Choices

72

73

```python

74

from interactions import slash_command, slash_option, SlashCommandChoice, SlashContext, OptionType

75

76

@slash_command(name="color", description="Choose a color")

77

@slash_option(

78

name="color_choice",

79

description="Pick your favorite color",

80

required=True,

81

opt_type=OptionType.STRING,

82

choices=[

83

SlashCommandChoice(name="Red", value="red"),

84

SlashCommandChoice(name="Blue", value="blue"),

85

SlashCommandChoice(name="Green", value="green"),

86

SlashCommandChoice(name="Yellow", value="yellow")

87

]

88

)

89

async def color_command(ctx: SlashContext, color_choice: str):

90

await ctx.send(f"You chose: {color_choice}")

91

```

92

93

### Subcommands

94

95

```python

96

from interactions import SlashCommand, subcommand, SlashContext

97

98

# Create base command group

99

base_cmd = SlashCommand(name="admin", description="Admin commands", group_name="administration")

100

101

@subcommand(base=base_cmd, name="ban", description="Ban a user")

102

@slash_option(name="user", description="User to ban", required=True, opt_type=OptionType.USER)

103

@slash_option(name="reason", description="Ban reason", required=False, opt_type=OptionType.STRING)

104

async def admin_ban(ctx: SlashContext, user: Member, reason: str = "No reason provided"):

105

await user.ban(reason=reason)

106

await ctx.send(f"Banned {user.mention} for: {reason}")

107

108

@subcommand(base=base_cmd, name="kick", description="Kick a user")

109

@slash_option(name="user", description="User to kick", required=True, opt_type=OptionType.USER)

110

async def admin_kick(ctx: SlashContext, user: Member):

111

await user.kick()

112

await ctx.send(f"Kicked {user.mention}")

113

```

114

115

### Slash Command Permissions

116

117

```python

118

from interactions import slash_command, slash_default_member_permission, Permissions

119

120

@slash_command(name="mod_only", description="Moderator only command")

121

@slash_default_member_permission(Permissions.MANAGE_MESSAGES)

122

async def mod_only_command(ctx: SlashContext):

123

await ctx.send("You have moderation permissions!")

124

```

125

126

## Context Menu Commands

127

128

### User Context Menu

129

130

```python

131

from interactions import context_menu, ContextMenuContext, CommandType

132

133

@context_menu(name="Get User Info", context_type=CommandType.USER)

134

async def user_info_menu(ctx: ContextMenuContext):

135

user = ctx.target # The user that was right-clicked

136

embed = Embed(

137

title=f"User Info: {user.username}",

138

description=f"ID: {user.id}\nCreated: {user.created_at}",

139

color=0x00ff00

140

)

141

await ctx.send(embed=embed, ephemeral=True)

142

```

143

144

### Message Context Menu

145

146

```python

147

from interactions import context_menu, ContextMenuContext, CommandType

148

149

@context_menu(name="Quote Message", context_type=CommandType.MESSAGE)

150

async def quote_menu(ctx: ContextMenuContext):

151

message = ctx.target # The message that was right-clicked

152

quote_embed = Embed(

153

description=message.content,

154

color=0x0099ff

155

)

156

quote_embed.set_author(

157

name=message.author.username,

158

icon_url=message.author.avatar.url if message.author.avatar else None

159

)

160

await ctx.send(f"Quote from {message.author.mention}:", embed=quote_embed)

161

```

162

163

### Generic Context Menu

164

165

```python

166

from interactions import context_menu, CommandType, ContextMenuContext

167

168

@context_menu(name="Custom Action", context_type=CommandType.USER)

169

async def custom_menu(ctx: ContextMenuContext):

170

if ctx.context_type == CommandType.USER:

171

target = ctx.target

172

await ctx.send(f"Action performed on user: {target.username}")

173

elif ctx.context_type == CommandType.MESSAGE:

174

target = ctx.target

175

await ctx.send(f"Action performed on message from: {target.author.username}")

176

```

177

178

## Command Context Classes

179

180

### Base Context

181

182

```python

183

class BaseContext:

184

bot: Client

185

author: Union[User, Member]

186

channel: MessageableChannel

187

guild: Optional[Guild]

188

message: Optional[Message]

189

created_at: datetime

190

```

191

192

### Interaction Context

193

194

```python

195

class InteractionContext(BaseContext):

196

interaction_id: Snowflake

197

token: str

198

application_id: Snowflake

199

type: InteractionType

200

data: dict

201

locale: str

202

guild_locale: Optional[str]

203

responded: bool

204

deferred: bool

205

ephemeral: bool

206

```

207

208

**Key Methods**:

209

- `send(content=None, **kwargs)` { .api } - Send response/followup

210

- `defer(ephemeral=False)` { .api } - Defer the interaction

211

- `edit(content=None, **kwargs)` { .api } - Edit original response

212

- `delete()` { .api } - Delete original response

213

- `followup(content=None, **kwargs)` { .api } - Send followup message

214

215

### Slash Context

216

217

```python

218

class SlashContext(InteractionContext):

219

command: SlashCommand

220

args: List[Any]

221

kwargs: Dict[str, Any]

222

options: List[dict]

223

focused_option: Optional[str] # For autocomplete

224

```

225

226

### Component Context

227

228

```python

229

class ComponentContext(InteractionContext):

230

component: BaseComponent

231

custom_id: str

232

component_type: ComponentType

233

values: List[str] # For select menus

234

```

235

236

### Modal Context

237

238

```python

239

class ModalContext(InteractionContext):

240

custom_id: str

241

components: List[dict]

242

values: Dict[str, str] # component_id -> value mapping

243

```

244

245

### Context Menu Context

246

247

```python

248

class ContextMenuContext(InteractionContext):

249

command_type: CommandType

250

target: Union[User, Member, Message]

251

target_id: Snowflake

252

```

253

254

**Properties**:

255

- `target_user` { .api } - Target user (if USER command)

256

- `target_message` { .api } - Target message (if MESSAGE command)

257

258

## Autocomplete

259

260

### Basic Autocomplete

261

262

```python

263

from interactions import slash_command, slash_option, AutocompleteContext, OptionType

264

265

@slash_command(name="search", description="Search for something")

266

@slash_option(

267

name="query",

268

description="Search query",

269

required=True,

270

opt_type=OptionType.STRING,

271

autocomplete=True

272

)

273

async def search_command(ctx: SlashContext, query: str):

274

await ctx.send(f"Searching for: {query}")

275

276

@search_command.autocomplete("query")

277

async def search_autocomplete(ctx: AutocompleteContext):

278

# Get user's current input

279

user_input = ctx.input_text

280

281

# Generate suggestions based on input

282

suggestions = [

283

{"name": f"Search: {user_input}", "value": user_input},

284

{"name": f"Advanced: {user_input}", "value": f"advanced:{user_input}"},

285

{"name": f"Exact: {user_input}", "value": f'"{user_input}"'}

286

]

287

288

# Return up to 25 suggestions

289

await ctx.send(suggestions[:25])

290

```

291

292

### Global Autocomplete

293

294

```python

295

from interactions import global_autocomplete, OptionType

296

297

@global_autocomplete("color")

298

async def color_autocomplete(ctx: AutocompleteContext):

299

"""Global autocomplete for any 'color' option"""

300

colors = ["red", "blue", "green", "yellow", "purple", "orange", "pink"]

301

user_input = ctx.input_text.lower()

302

303

# Filter colors based on user input

304

matching_colors = [c for c in colors if user_input in c.lower()]

305

306

suggestions = [{"name": color.title(), "value": color} for color in matching_colors]

307

await ctx.send(suggestions[:25])

308

```

309

310

## Response Types

311

312

### Basic Responses

313

314

```python

315

# Send simple message

316

await ctx.send("Hello World!")

317

318

# Send ephemeral message (only visible to user)

319

await ctx.send("Secret message!", ephemeral=True)

320

321

# Send with embed

322

embed = Embed(title="Title", description="Description", color=0x00ff00)

323

await ctx.send(embed=embed)

324

325

# Send with file

326

file = File("path/to/image.png")

327

await ctx.send("Here's an image:", file=file)

328

```

329

330

### Advanced Responses

331

332

```python

333

from interactions import Button, ActionRow, ButtonStyle

334

335

# Send with components

336

button = Button(

337

style=ButtonStyle.PRIMARY,

338

label="Click Me!",

339

custom_id="my_button"

340

)

341

action_row = ActionRow(button)

342

await ctx.send("Click the button below:", components=[action_row])

343

344

# Send with multiple embeds

345

embed1 = Embed(title="First", description="First embed")

346

embed2 = Embed(title="Second", description="Second embed")

347

await ctx.send(embeds=[embed1, embed2])

348

349

# Send with allowed mentions control

350

from interactions import AllowedMentions

351

mentions = AllowedMentions(users=False, roles=False, everyone=False)

352

await ctx.send("@everyone This won't ping!", allowed_mentions=mentions)

353

```

354

355

### Deferred Responses

356

357

```python

358

# Defer for long operations

359

@slash_command(name="slow", description="A slow command")

360

async def slow_command(ctx: SlashContext):

361

await ctx.defer() # Shows "Bot is thinking..."

362

363

# Do slow work here

364

await asyncio.sleep(5)

365

366

# Send the actual response

367

await ctx.send("Done with slow operation!")

368

369

# Defer ephemeral

370

@slash_command(name="secret_slow", description="A slow secret command")

371

async def secret_slow_command(ctx: SlashContext):

372

await ctx.defer(ephemeral=True)

373

374

# Do work...

375

await asyncio.sleep(3)

376

377

await ctx.send("Secret result!", ephemeral=True)

378

```

379

380

### Edit Responses

381

382

```python

383

@slash_command(name="countdown", description="Count down from 5")

384

async def countdown_command(ctx: SlashContext):

385

# Send initial response

386

await ctx.send("5...")

387

388

# Edit the response multiple times

389

for i in range(4, 0, -1):

390

await asyncio.sleep(1)

391

await ctx.edit(f"{i}...")

392

393

await asyncio.sleep(1)

394

await ctx.edit("🎉 Done!")

395

```

396

397

### Followup Messages

398

399

```python

400

@slash_command(name="multi", description="Send multiple messages")

401

async def multi_command(ctx: SlashContext):

402

# Initial response

403

await ctx.send("First message!")

404

405

# Additional messages via followup

406

await ctx.followup("Second message!")

407

await ctx.followup("Third message!", ephemeral=True)

408

409

# Followups return Message objects

410

msg = await ctx.followup("Fourth message - I can edit this!")

411

await asyncio.sleep(2)

412

await msg.edit("Edited the fourth message!")

413

```

414

415

## Command Classes

416

417

### Slash Command Class

418

419

```python

420

class SlashCommand:

421

name: str

422

description: str

423

options: List[SlashCommandOption]

424

callback: Callable

425

group_name: Optional[str]

426

sub_cmd_name: Optional[str]

427

dm_permission: bool

428

default_member_permissions: Optional[Permissions]

429

nsfw: bool

430

```

431

432

### Context Menu Class

433

434

```python

435

class ContextMenu:

436

name: str

437

type: CommandType

438

callback: Callable

439

dm_permission: bool

440

default_member_permissions: Optional[Permissions]

441

nsfw: bool

442

```

443

444

### Command Options

445

446

```python

447

class SlashCommandOption:

448

name: str

449

description: str

450

type: OptionType

451

required: bool

452

choices: Optional[List[SlashCommandChoice]]

453

options: Optional[List[SlashCommandOption]] # For subcommands

454

channel_types: Optional[List[ChannelType]]

455

min_value: Optional[Union[int, float]]

456

max_value: Optional[Union[int, float]]

457

min_length: Optional[int]

458

max_length: Optional[int]

459

autocomplete: bool

460

461

class SlashCommandChoice:

462

name: str

463

value: Union[str, int, float]

464

name_localizations: Optional[Dict[str, str]]

465

```

466

467

### Option Types

468

469

```python

470

from interactions import OptionType

471

472

OptionType.STRING # Text input

473

OptionType.INTEGER # Whole number

474

OptionType.BOOLEAN # True/False

475

OptionType.USER # Discord user

476

OptionType.CHANNEL # Discord channel

477

OptionType.ROLE # Discord role

478

OptionType.MENTIONABLE # User or role

479

OptionType.NUMBER # Decimal number

480

OptionType.ATTACHMENT # File attachment

481

```

482

483

## Advanced Features

484

485

### Command Localization

486

487

```python

488

from interactions import LocalizedName, LocalizedDesc

489

490

@slash_command(

491

name=LocalizedName(default="hello", **{"es-ES": "hola", "fr": "bonjour"}),

492

description=LocalizedDesc(default="Say hello", **{"es-ES": "Di hola", "fr": "Dire bonjour"})

493

)

494

async def localized_command(ctx: SlashContext):

495

await ctx.send("Hello! / ¡Hola! / Bonjour!")

496

```

497

498

### Command Synchronization

499

500

```python

501

# Check if commands need syncing

502

if interactions.sync_needed(bot.interactions):

503

await bot.sync_interactions()

504

505

# Convert commands to dict format

506

commands_dict = interactions.application_commands_to_dict(bot.interactions)

507

```

508

509

### Command Groups

510

511

```python

512

# Create command group

513

admin_group = SlashCommand(

514

name="admin",

515

description="Admin commands",

516

group_name="administration"

517

)

518

519

# Commands with same base form a group

520

@subcommand(base=admin_group, name="users", description="Manage users")

521

async def admin_users(ctx: SlashContext):

522

pass

523

524

@subcommand(base=admin_group, name="channels", description="Manage channels")

525

async def admin_channels(ctx: SlashContext):

526

pass

527

```