or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

advanced-features.mdcore-application.mdindex.mdmiddleware.mdreceivers.mdrequest-verification.md

advanced-features.mddocs/

0

# Advanced Features

1

2

Slack Bolt provides advanced functionality for AI Assistant integration, workflow steps, custom functions, and conversation state management for complex Slack application scenarios.

3

4

## Capabilities

5

6

### AI Assistant Integration

7

8

Build AI-powered Slack assistants with thread context management and user interaction handling.

9

10

```typescript { .api }

11

/**

12

* AI Assistant class for building intelligent Slack applications

13

* @param config - Assistant configuration with event handlers

14

*/

15

class Assistant {

16

constructor(config: AssistantConfig);

17

}

18

19

interface AssistantConfig {

20

/** Custom thread context store (defaults to in-memory store) */

21

threadContextStore?: AssistantThreadContextStore;

22

/** Handler(s) for when assistant threads are started */

23

threadStarted: AssistantThreadStartedMiddleware | AssistantThreadStartedMiddleware[];

24

/** Handler(s) for when thread context changes (optional) */

25

threadContextChanged?: AssistantThreadContextChangedMiddleware | AssistantThreadContextChangedMiddleware[];

26

/** Handler(s) for user messages in assistant threads */

27

userMessage: AssistantUserMessageMiddleware | AssistantUserMessageMiddleware[];

28

}

29

30

type AssistantThreadStartedMiddleware = (

31

args: AssistantUtilityArgs & AllMiddlewareArgs

32

) => Promise<void>;

33

34

type AssistantThreadContextChangedMiddleware = (

35

args: AssistantUtilityArgs & AllMiddlewareArgs & {

36

previousThreadContext?: AssistantThreadContext;

37

}

38

) => Promise<void>;

39

40

type AssistantUserMessageMiddleware = (

41

args: AssistantUtilityArgs & SlackEventMiddlewareArgs<'message'> & {

42

message: AssistantMessage;

43

}

44

) => Promise<void>;

45

```

46

47

**Usage Examples:**

48

49

```typescript

50

import { App, Assistant } from "@slack/bolt";

51

52

const app = new App({

53

token: process.env.SLACK_BOT_TOKEN,

54

signingSecret: process.env.SLACK_SIGNING_SECRET

55

});

56

57

// Configure assistant

58

const assistant = new Assistant({

59

threadStarted: async ({ say, setStatus, setSuggestedPrompts }) => {

60

await say("Hello! I'm your AI assistant. How can I help you today?");

61

62

await setStatus("Ready to assist");

63

64

await setSuggestedPrompts({

65

prompts: [

66

{ title: "Help me write code", message: "Can you help me write some code?" },

67

{ title: "Explain a concept", message: "Can you explain how webhooks work?" },

68

{ title: "Review my work", message: "Can you review this document?" }

69

],

70

title: "Popular requests"

71

});

72

},

73

74

userMessage: async ({

75

message,

76

say,

77

getThreadContext,

78

saveThreadContext,

79

setStatus

80

}) => {

81

await setStatus("Thinking...");

82

83

// Get conversation context

84

const context = await getThreadContext();

85

86

// Process user message with AI

87

const response = await processWithAI(message.text, context);

88

89

// Update context with new information

90

context.conversationHistory.push({

91

user: message.text,

92

assistant: response

93

});

94

95

// Save updated context

96

await saveThreadContext();

97

98

await say(response);

99

await setStatus("Ready");

100

}

101

});

102

103

// Register assistant with app

104

app.assistant(assistant);

105

```

106

107

### Assistant Thread Context

108

109

Manage conversation state and context across assistant interactions.

110

111

```typescript { .api }

112

interface AssistantThreadContext {

113

/** Channel ID where the thread exists */

114

channelId: string;

115

/** Thread timestamp identifier */

116

threadTs: string;

117

/** Custom context data */

118

[key: string]: any;

119

}

120

121

interface AssistantThreadContextStore {

122

/** Retrieve context for a specific thread */

123

get(channelId: string, threadTs: string): Promise<AssistantThreadContext>;

124

/** Save context for a specific thread */

125

save(context: AssistantThreadContext): Promise<void>;

126

/** Remove context for a specific thread */

127

remove(channelId: string, threadTs: string): Promise<void>;

128

}

129

130

class DefaultThreadContextStore implements AssistantThreadContextStore {

131

constructor();

132

133

async get(channelId: string, threadTs: string): Promise<AssistantThreadContext>;

134

async save(context: AssistantThreadContext): Promise<void>;

135

async remove(channelId: string, threadTs: string): Promise<void>;

136

}

137

```

138

139

### Assistant Utilities

140

141

Utility functions available to assistant middleware for managing thread state and interactions.

142

143

```typescript { .api }

144

interface AssistantUtilityArgs {

145

/** Get current thread context */

146

getThreadContext: GetThreadContextUtilFn;

147

/** Save current thread context */

148

saveThreadContext: SaveThreadContextUtilFn;

149

/** Send message in current thread */

150

say: SayFn;

151

/** Set assistant status */

152

setStatus: SetStatusFn;

153

/** Set suggested prompts for the thread */

154

setSuggestedPrompts: SetSuggestedPromptsFn;

155

/** Set thread title */

156

setTitle: SetTitleFn;

157

}

158

159

type GetThreadContextUtilFn = () => Promise<AssistantThreadContext>;

160

type SaveThreadContextUtilFn = () => Promise<void>;

161

type SetStatusFn = (status: string) => Promise<AssistantThreadsSetStatusResponse>;

162

type SetSuggestedPromptsFn = (

163

params: SetSuggestedPromptsArguments

164

) => Promise<AssistantThreadsSetSuggestedPromptsResponse>;

165

type SetTitleFn = (title: string) => Promise<AssistantThreadsSetTitleResponse>;

166

167

interface SetSuggestedPromptsArguments {

168

/** Prompt suggestions that appear when opening assistant thread */

169

prompts: [AssistantPrompt, ...AssistantPrompt[]];

170

/** Title for the prompts */

171

title: string;

172

}

173

174

interface AssistantPrompt {

175

/** Display title for the prompt */

176

title: string;

177

/** Message text when prompt is selected */

178

message: string;

179

}

180

```

181

182

### Workflow Steps (Deprecated)

183

184

Legacy workflow step functionality for workflow apps (deprecated in favor of custom functions).

185

186

```typescript { .api }

187

/**

188

* @deprecated Steps from Apps are no longer supported and support will be removed in next major version

189

* Workflow step builder for creating custom workflow steps

190

*/

191

class WorkflowStep {

192

constructor(config: WorkflowStepConfig);

193

}

194

195

/**

196

* @deprecated Configuration for workflow steps

197

*/

198

interface WorkflowStepConfig {

199

/** Callback ID for the workflow step */

200

callback_id: string;

201

/** Handler for step edit action */

202

edit: WorkflowStepEditMiddleware | WorkflowStepEditMiddleware[];

203

/** Handler for step save action */

204

save: WorkflowStepSaveMiddleware | WorkflowStepSaveMiddleware[];

205

/** Handler for step execution */

206

execute: WorkflowStepExecuteMiddleware | WorkflowStepExecuteMiddleware[];

207

}

208

209

type WorkflowStepEditMiddleware = (

210

args: SlackActionMiddlewareArgs<WorkflowStepEdit> & {

211

step: WorkflowStepEdit;

212

configure: (config: StepConfigureArguments) => Promise<ViewsOpenResponse>;

213

}

214

) => Promise<void>;

215

216

type WorkflowStepSaveMiddleware = (

217

args: SlackViewMiddlewareArgs & {

218

step: WorkflowStepEdit;

219

update: (config: StepUpdateArguments) => Promise<WorkflowsUpdateStepResponse>;

220

}

221

) => Promise<void>;

222

223

type WorkflowStepExecuteMiddleware = (

224

args: SlackEventMiddlewareArgs<'workflow_step_execute'> & {

225

step: WorkflowStepExecuteEvent;

226

complete: (outputs?: StepCompletionArguments) => Promise<WorkflowsStepCompletedResponse>;

227

fail: (error: StepFailureArguments) => Promise<WorkflowsStepFailedResponse>;

228

}

229

) => Promise<void>;

230

```

231

232

### Custom Functions

233

234

Create custom functions for Slack workflows with input validation and execution handling.

235

236

```typescript { .api }

237

/**

238

* Custom function builder for Slack workflows

239

*/

240

class CustomFunction {

241

constructor(callbackId: string, config: CustomFunctionConfig);

242

}

243

244

interface CustomFunctionConfig {

245

/** Handler for function execution */

246

execute: CustomFunctionExecuteMiddleware | CustomFunctionExecuteMiddleware[];

247

}

248

249

type CustomFunctionExecuteMiddleware = (

250

args: SlackCustomFunctionMiddlewareArgs & {

251

inputs: FunctionInputs;

252

complete: FunctionCompleteFn;

253

fail: FunctionFailFn;

254

}

255

) => Promise<void>;

256

257

type FunctionCompleteFn = (outputs: { [key: string]: any }) => Promise<void>;

258

type FunctionFailFn = (error: string) => Promise<void>;

259

260

interface SlackCustomFunctionMiddlewareArgs extends AllMiddlewareArgs {

261

/** Function execution payload */

262

payload: {

263

type: 'function_executed';

264

function: {

265

callback_id: string;

266

type: 'app';

267

};

268

inputs: FunctionInputs;

269

function_execution_id: string;

270

workflow: {

271

id: string;

272

};

273

event: {

274

type: 'function_executed';

275

};

276

};

277

}

278

```

279

280

**Usage Examples:**

281

282

```typescript

283

import { App, CustomFunction } from "@slack/bolt";

284

285

const app = new App({

286

token: process.env.SLACK_BOT_TOKEN,

287

signingSecret: process.env.SLACK_SIGNING_SECRET

288

});

289

290

// Define custom function

291

const processDataFunction = new CustomFunction("process_data", {

292

execute: async ({ inputs, complete, fail, client }) => {

293

try {

294

const { data_source, format } = inputs;

295

296

// Validate inputs

297

if (!data_source) {

298

await fail("data_source is required");

299

return;

300

}

301

302

// Process the data

303

const result = await processData(data_source, format);

304

305

// Return outputs

306

await complete({

307

processed_data: result.data,

308

record_count: result.count,

309

status: "success"

310

});

311

312

} catch (error) {

313

await fail(`Processing failed: ${error.message}`);

314

}

315

}

316

});

317

318

// Register function with app

319

app.function("process_data", processDataFunction);

320

```

321

322

### Conversation Store

323

324

Manage conversation state and context across multiple interactions.

325

326

```typescript { .api }

327

/**

328

* Interface for storing conversation state

329

*/

330

interface ConversationStore {

331

/** Store conversation data */

332

set(conversationId: string, value: any, expiresAt?: number): Promise<void>;

333

/** Retrieve conversation data */

334

get<T = any>(conversationId: string): Promise<T | undefined>;

335

/** Remove conversation data */

336

delete(conversationId: string): Promise<void>;

337

}

338

339

/**

340

* In-memory implementation of ConversationStore

341

*/

342

class MemoryStore implements ConversationStore {

343

constructor();

344

345

async set(conversationId: string, value: any, expiresAt?: number): Promise<void>;

346

async get<T = any>(conversationId: string): Promise<T | undefined>;

347

async delete(conversationId: string): Promise<void>;

348

}

349

350

/**

351

* Middleware for adding conversation context to requests

352

* @param store - Conversation store instance

353

* @param options - Context options

354

*/

355

function conversationContext(

356

store: ConversationStore,

357

options?: ConversationContextOptions

358

): Middleware<AnyMiddlewareArgs>;

359

360

interface ConversationContextOptions {

361

/** Custom function to extract conversation ID */

362

getConversationId?: (args: AnyMiddlewareArgs) => string | undefined;

363

/** Context property name (defaults to 'conversation') */

364

contextKey?: string;

365

}

366

```

367

368

**Usage Examples:**

369

370

```typescript

371

import { App, MemoryStore, conversationContext } from "@slack/bolt";

372

373

const app = new App({

374

token: process.env.SLACK_BOT_TOKEN,

375

signingSecret: process.env.SLACK_SIGNING_SECRET

376

});

377

378

// Create conversation store

379

const convoStore = new MemoryStore();

380

381

// Add conversation context middleware

382

app.use(conversationContext(convoStore));

383

384

// Use conversation context in listeners

385

app.message("start survey", async ({ message, context, say }) => {

386

// Initialize conversation state

387

await context.conversation.set("survey_step", 1);

388

await context.conversation.set("responses", {});

389

390

await say("Let's start the survey! What's your name?");

391

});

392

393

app.message(async ({ message, context, say }) => {

394

const step = await context.conversation.get("survey_step");

395

const responses = await context.conversation.get("responses") || {};

396

397

if (step === 1) {

398

responses.name = message.text;

399

await context.conversation.set("survey_step", 2);

400

await context.conversation.set("responses", responses);

401

402

await say("Thanks! What's your favorite color?");

403

} else if (step === 2) {

404

responses.color = message.text;

405

await context.conversation.set("survey_step", 3);

406

await context.conversation.set("responses", responses);

407

408

await say(`Great! So your name is ${responses.name} and your favorite color is ${responses.color}. Survey complete!`);

409

410

// Clear conversation state

411

await context.conversation.delete("survey_step");

412

await context.conversation.delete("responses");

413

}

414

});

415

```