or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

activity-handling.mdbot-adapters.mdindex.mdmessage-factories.mdmiddleware.mdoauth-authentication.mdstate-management.mdstorage.mdtelemetry-logging.mdtesting-utilities.mdturn-context.md

middleware.mddocs/

0

# Middleware

1

2

Middleware pipeline for implementing cross-cutting concerns like logging, telemetry, typing indicators, and automatic state saving. Middleware components can inspect and modify activities as they flow through the bot.

3

4

## Capabilities

5

6

### Middleware Base Class

7

8

Abstract base class that defines the interface for all middleware components in the Bot Framework pipeline, providing the foundation for implementing cross-cutting concerns.

9

10

```python { .api }

11

class Middleware:

12

async def on_turn(self, turn_context: TurnContext, next_middleware):

13

"""

14

Process the turn. Must be implemented by derived classes.

15

16

Args:

17

turn_context (TurnContext): Current turn context

18

next_middleware: Function to call the next middleware in pipeline

19

"""

20

```

21

22

### MiddlewareSet

23

24

Collection that manages middleware components and provides the pipeline execution mechanism for processing activities through registered middleware.

25

26

```python { .api }

27

class MiddlewareSet:

28

def __init__(self):

29

"""Initialize empty middleware set."""

30

31

def use(self, middleware):

32

"""

33

Add middleware to the set.

34

35

Args:

36

middleware (Middleware): Middleware to add

37

38

Returns:

39

MiddlewareSet: Self for method chaining

40

"""

41

42

async def receive_activity_with_status(self, turn_context: TurnContext, callback):

43

"""

44

Execute middleware pipeline with status handling.

45

46

Args:

47

turn_context (TurnContext): Current turn context

48

callback: Final callback to execute

49

50

Returns:

51

int: HTTP status code

52

"""

53

54

async def receive_activity(self, turn_context: TurnContext, callback):

55

"""

56

Execute middleware pipeline.

57

58

Args:

59

turn_context (TurnContext): Current turn context

60

callback: Final callback to execute

61

"""

62

```

63

64

### AutoSaveStateMiddleware

65

66

Automatically saves bot state after each turn completes, ensuring state changes are persisted without requiring manual save operations in bot logic.

67

68

```python { .api }

69

class AutoSaveStateMiddleware(Middleware):

70

def __init__(self, *bot_states):

71

"""

72

Initialize auto-save state middleware.

73

74

Args:

75

*bot_states: Variable number of BotState objects to auto-save

76

"""

77

78

async def on_turn(self, turn_context: TurnContext, next_middleware):

79

"""

80

Execute middleware and auto-save states.

81

82

Args:

83

turn_context (TurnContext): Current turn context

84

next_middleware: Next middleware function

85

"""

86

```

87

88

### ShowTypingMiddleware

89

90

Shows typing indicator to users while the bot is processing their message, providing better user experience by indicating bot activity.

91

92

```python { .api }

93

class ShowTypingMiddleware(Middleware):

94

def __init__(self, delay: float = 0.5, period: float = 2.0):

95

"""

96

Initialize show typing middleware.

97

98

Args:

99

delay (float): Delay before showing typing indicator (seconds)

100

period (float): How often to send typing indicator (seconds)

101

"""

102

103

async def on_turn(self, turn_context: TurnContext, next_middleware):

104

"""

105

Execute middleware with typing indicators.

106

107

Args:

108

turn_context (TurnContext): Current turn context

109

next_middleware: Next middleware function

110

"""

111

```

112

113

### TelemetryLoggerMiddleware

114

115

Logs telemetry data for bot activities, enabling monitoring, analytics, and debugging of bot interactions and performance.

116

117

```python { .api }

118

class TelemetryLoggerMiddleware(Middleware):

119

def __init__(self, telemetry_client, log_personal_information: bool = False):

120

"""

121

Initialize telemetry logger middleware.

122

123

Args:

124

telemetry_client (BotTelemetryClient): Telemetry client

125

log_personal_information (bool): Whether to log PII

126

"""

127

128

async def on_turn(self, turn_context: TurnContext, next_middleware):

129

"""

130

Execute middleware with telemetry logging.

131

132

Args:

133

turn_context (TurnContext): Current turn context

134

next_middleware: Next middleware function

135

"""

136

137

async def on_receive_activity(self, activity):

138

"""

139

Log received activity.

140

141

Args:

142

activity (Activity): Received activity

143

"""

144

145

async def on_send_activity(self, activity):

146

"""

147

Log sent activity.

148

149

Args:

150

activity (Activity): Sent activity

151

"""

152

153

async def on_update_activity(self, activity):

154

"""

155

Log updated activity.

156

157

Args:

158

activity (Activity): Updated activity

159

"""

160

161

async def on_delete_activity(self, activity):

162

"""

163

Log deleted activity.

164

165

Args:

166

activity (Activity): Deleted activity

167

"""

168

```

169

170

### RegisterClassMiddleware

171

172

Registers classes for dependency injection in the turn context, enabling access to services and utilities throughout the middleware pipeline and bot logic.

173

174

```python { .api }

175

class RegisterClassMiddleware(Middleware):

176

def __init__(self, classes_to_register: dict):

177

"""

178

Initialize register class middleware.

179

180

Args:

181

classes_to_register (dict): Dictionary of class name to class instance

182

"""

183

184

async def on_turn(self, turn_context: TurnContext, next_middleware):

185

"""

186

Execute middleware with class registration.

187

188

Args:

189

turn_context (TurnContext): Current turn context

190

next_middleware: Next middleware function

191

"""

192

```

193

194

### TranscriptLoggerMiddleware

195

196

Logs complete conversation transcripts for audit, compliance, and debugging purposes, storing the full conversation history.

197

198

```python { .api }

199

class TranscriptLoggerMiddleware(Middleware):

200

def __init__(self, transcript_logger):

201

"""

202

Initialize transcript logger middleware.

203

204

Args:

205

transcript_logger (TranscriptLogger): Transcript logger implementation

206

"""

207

208

async def on_turn(self, turn_context: TurnContext, next_middleware):

209

"""

210

Execute middleware with transcript logging.

211

212

Args:

213

turn_context (TurnContext): Current turn context

214

next_middleware: Next middleware function

215

"""

216

```

217

218

### AnonymousReceiveMiddleware

219

220

Wrapper that allows using anonymous functions or lambdas as middleware, providing a simple way to add custom middleware logic.

221

222

```python { .api }

223

class AnonymousReceiveMiddleware(Middleware):

224

def __init__(self, anonymous_method):

225

"""

226

Initialize anonymous middleware.

227

228

Args:

229

anonymous_method: Function to execute as middleware

230

"""

231

232

async def on_turn(self, turn_context: TurnContext, next_middleware):

233

"""

234

Execute anonymous middleware function.

235

236

Args:

237

turn_context (TurnContext): Current turn context

238

next_middleware: Next middleware function

239

"""

240

```

241

242

## Usage Examples

243

244

### Basic Middleware Setup

245

246

```python

247

from botbuilder.core import (

248

BotFrameworkAdapter, MiddlewareSet, AutoSaveStateMiddleware,

249

ShowTypingMiddleware, ConversationState, UserState, MemoryStorage

250

)

251

252

# Create adapter

253

adapter = BotFrameworkAdapter(settings)

254

255

# Create states

256

memory_storage = MemoryStorage()

257

conversation_state = ConversationState(memory_storage)

258

user_state = UserState(memory_storage)

259

260

# Add middleware to adapter

261

adapter.use(ShowTypingMiddleware(delay=0.5, period=2.0))

262

adapter.use(AutoSaveStateMiddleware(conversation_state, user_state))

263

```

264

265

### Custom Middleware Implementation

266

267

```python

268

from botbuilder.core import Middleware, TurnContext, MessageFactory

269

270

class LoggingMiddleware(Middleware):

271

async def on_turn(self, turn_context: TurnContext, next_middleware):

272

# Log incoming activity

273

print(f"Incoming: {turn_context.activity.type} - {turn_context.activity.text}")

274

275

# Continue pipeline

276

await next_middleware()

277

278

# Log after processing

279

print(f"Completed processing for turn")

280

281

class ProfanityFilterMiddleware(Middleware):

282

def __init__(self, bad_words: list):

283

self.bad_words = [word.lower() for word in bad_words]

284

285

async def on_turn(self, turn_context: TurnContext, next_middleware):

286

if turn_context.activity.type == "message":

287

text = turn_context.activity.text.lower()

288

289

# Check for profanity

290

if any(bad_word in text for bad_word in self.bad_words):

291

await turn_context.send_activity(

292

MessageFactory.text("Please keep the conversation respectful.")

293

)

294

return # Don't continue pipeline

295

296

# Continue pipeline

297

await next_middleware()

298

299

# Usage

300

adapter.use(LoggingMiddleware())

301

adapter.use(ProfanityFilterMiddleware(["badword1", "badword2"]))

302

```

303

304

### Telemetry Middleware Setup

305

306

```python

307

from botbuilder.core import TelemetryLoggerMiddleware, NullTelemetryClient

308

309

# Create telemetry client (use actual implementation in production)

310

telemetry_client = NullTelemetryClient()

311

312

# Create telemetry middleware

313

telemetry_middleware = TelemetryLoggerMiddleware(

314

telemetry_client,

315

log_personal_information=False # Set to False for privacy

316

)

317

318

# Add to adapter

319

adapter.use(telemetry_middleware)

320

```

321

322

### Anonymous Middleware

323

324

```python

325

from botbuilder.core import AnonymousReceiveMiddleware

326

327

# Simple logging middleware using lambda

328

logging_middleware = AnonymousReceiveMiddleware(

329

lambda turn_context, next_middleware: self.log_and_continue(turn_context, next_middleware)

330

)

331

332

async def log_and_continue(self, turn_context, next_middleware):

333

print(f"Processing message: {turn_context.activity.text}")

334

await next_middleware()

335

print("Message processed")

336

337

adapter.use(logging_middleware)

338

339

# Or inline with async lambda (Python 3.5+)

340

adapter.use(AnonymousReceiveMiddleware(

341

lambda turn_context, next_middleware: self.simple_log(turn_context, next_middleware)

342

))

343

```

344

345

### Middleware with Service Registration

346

347

```python

348

from botbuilder.core import RegisterClassMiddleware

349

350

class CustomService:

351

def __init__(self):

352

self.data = {}

353

354

def get_data(self, key):

355

return self.data.get(key)

356

357

def set_data(self, key, value):

358

self.data[key] = value

359

360

# Register service

361

custom_service = CustomService()

362

service_middleware = RegisterClassMiddleware({

363

"CustomService": custom_service

364

})

365

366

adapter.use(service_middleware)

367

368

# Access in bot

369

class ServiceBot(ActivityHandler):

370

async def on_message_activity(self, turn_context: TurnContext):

371

# Get service from turn context

372

custom_service = turn_context.services.get("CustomService")

373

374

if custom_service:

375

custom_service.set_data("last_message", turn_context.activity.text)

376

await turn_context.send_activity(

377

MessageFactory.text("Message saved to service!")

378

)

379

```

380

381

### Conditional Middleware

382

383

```python

384

class ConditionalMiddleware(Middleware):

385

def __init__(self, condition_func, target_middleware):

386

self.condition_func = condition_func

387

self.target_middleware = target_middleware

388

389

async def on_turn(self, turn_context: TurnContext, next_middleware):

390

# Check condition

391

if self.condition_func(turn_context):

392

# Execute target middleware

393

await self.target_middleware.on_turn(turn_context, next_middleware)

394

else:

395

# Skip target middleware

396

await next_middleware()

397

398

# Usage - only show typing for long messages

399

def is_long_message(turn_context):

400

return (turn_context.activity.type == "message" and

401

len(turn_context.activity.text or "") > 50)

402

403

conditional_typing = ConditionalMiddleware(

404

is_long_message,

405

ShowTypingMiddleware(delay=0.2, period=1.0)

406

)

407

408

adapter.use(conditional_typing)

409

```

410

411

### Error Handling Middleware

412

413

```python

414

class ErrorHandlingMiddleware(Middleware):

415

async def on_turn(self, turn_context: TurnContext, next_middleware):

416

try:

417

await next_middleware()

418

except Exception as e:

419

print(f"Error in bot: {e}")

420

421

# Send error message to user

422

await turn_context.send_activity(

423

MessageFactory.text("Sorry, something went wrong. Please try again.")

424

)

425

426

# Log error for debugging

427

# In production, you might want to send this to a logging service

428

429

# Add error handling as first middleware

430

adapter.use(ErrorHandlingMiddleware())

431

```

432

433

### Performance Monitoring Middleware

434

435

```python

436

import time

437

from botbuilder.core import Middleware

438

439

class PerformanceMiddleware(Middleware):

440

async def on_turn(self, turn_context: TurnContext, next_middleware):

441

start_time = time.time()

442

443

try:

444

await next_middleware()

445

finally:

446

duration = time.time() - start_time

447

print(f"Turn completed in {duration:.2f} seconds")

448

449

# Log slow turns

450

if duration > 2.0:

451

print(f"SLOW TURN: {duration:.2f}s for message: {turn_context.activity.text}")

452

453

adapter.use(PerformanceMiddleware())

454

```

455

456

### Middleware Ordering

457

458

```python

459

# Order matters! Middleware executes in registration order

460

# Error handling should be first

461

adapter.use(ErrorHandlingMiddleware())

462

463

# Performance monitoring

464

adapter.use(PerformanceMiddleware())

465

466

# Typing indicator

467

adapter.use(ShowTypingMiddleware())

468

469

# Service registration

470

adapter.use(RegisterClassMiddleware(services))

471

472

# Telemetry logging

473

adapter.use(TelemetryLoggerMiddleware(telemetry_client))

474

475

# Auto-save state (should be last)

476

adapter.use(AutoSaveStateMiddleware(conversation_state, user_state))

477

```

478

479

## Types

480

481

```python { .api }

482

class NextDelegate:

483

"""Delegate for calling next middleware in pipeline."""

484

async def __call__(self):

485

"""Execute next middleware."""

486

pass

487

488

class ReceiveActivityDelegate:

489

"""Delegate for receiving activities."""

490

async def __call__(self, turn_context: TurnContext):

491

"""Process turn context."""

492

pass

493

```