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

storage.mddocs/

0

# Storage

1

2

Storage implementations for persisting bot state and data. Includes memory storage for development and testing, plus abstract base classes for implementing custom storage solutions.

3

4

## Capabilities

5

6

### Storage Base Class

7

8

Abstract base class that defines the interface for all storage implementations in the Bot Framework, providing methods for reading, writing, and deleting data with support for concurrency control through eTags.

9

10

```python { .api }

11

class Storage:

12

async def read(self, keys):

13

"""

14

Read items from storage.

15

16

Args:

17

keys (list): List of keys to read

18

19

Returns:

20

dict: Dictionary of key-value pairs for found items

21

"""

22

23

async def write(self, changes):

24

"""

25

Write items to storage.

26

27

Args:

28

changes (dict): Dictionary of key-value pairs to write

29

"""

30

31

async def delete(self, keys):

32

"""

33

Delete items from storage.

34

35

Args:

36

keys (list): List of keys to delete

37

"""

38

```

39

40

### MemoryStorage

41

42

In-memory storage implementation for development and testing. Data is stored in memory and will be lost when the application restarts.

43

44

```python { .api }

45

class MemoryStorage(Storage):

46

def __init__(self, dictionary: dict = None):

47

"""

48

Initialize memory storage.

49

50

Args:

51

dictionary (dict, optional): Optional initial dictionary

52

"""

53

54

async def read(self, keys):

55

"""

56

Read items from memory storage.

57

58

Args:

59

keys (list): List of keys to read

60

61

Returns:

62

dict: Dictionary of found items

63

"""

64

65

async def write(self, changes):

66

"""

67

Write items to memory storage.

68

69

Args:

70

changes (dict): Dictionary of changes to write

71

"""

72

73

async def delete(self, keys):

74

"""

75

Delete items from memory storage.

76

77

Args:

78

keys (list): List of keys to delete

79

"""

80

```

81

82

### StoreItem

83

84

Base class for items that can be stored in bot storage, providing eTag support for concurrency control and change detection.

85

86

```python { .api }

87

class StoreItem:

88

def __init__(self):

89

"""Initialize store item with default eTag."""

90

self.e_tag = "*"

91

```

92

93

### QueueStorage

94

95

Queue-based storage implementation that provides FIFO (First-In-First-Out) storage capabilities for scenarios requiring ordered data processing.

96

97

```python { .api }

98

class QueueStorage:

99

def __init__(self, queues: dict = None):

100

"""

101

Initialize queue storage.

102

103

Args:

104

queues (dict, optional): Optional initial queues dictionary

105

"""

106

107

async def queue_activity(self, queue_name: str, activity):

108

"""

109

Add activity to a queue.

110

111

Args:

112

queue_name (str): Name of the queue

113

activity: Activity to queue

114

"""

115

116

async def dequeue_activity(self, queue_name: str):

117

"""

118

Remove and return activity from queue.

119

120

Args:

121

queue_name (str): Name of the queue

122

123

Returns:

124

Activity or None: Dequeued activity or None if queue is empty

125

"""

126

127

async def get_queue_length(self, queue_name: str):

128

"""

129

Get length of a queue.

130

131

Args:

132

queue_name (str): Name of the queue

133

134

Returns:

135

int: Number of items in queue

136

"""

137

```

138

139

### Storage Utilities

140

141

Utility functions for working with storage implementations and data serialization.

142

143

```python { .api }

144

def calculate_change_hash(obj):

145

"""

146

Calculate hash for change detection.

147

148

Args:

149

obj: Object to calculate hash for

150

151

Returns:

152

str: Hash string for the object

153

"""

154

155

def sanitize_key(key: str):

156

"""

157

Sanitize storage key to ensure compatibility.

158

159

Args:

160

key (str): Key to sanitize

161

162

Returns:

163

str: Sanitized key

164

"""

165

```

166

167

## Usage Examples

168

169

### Basic Memory Storage Setup

170

171

```python

172

from botbuilder.core import MemoryStorage, ConversationState, UserState

173

174

# Create memory storage

175

memory_storage = MemoryStorage()

176

177

# Use with bot states

178

conversation_state = ConversationState(memory_storage)

179

user_state = UserState(memory_storage)

180

181

# Storage is now ready to use with your bot

182

```

183

184

### Direct Storage Operations

185

186

```python

187

from botbuilder.core import MemoryStorage

188

189

# Create storage

190

storage = MemoryStorage()

191

192

# Write data directly

193

changes = {

194

"user:123": {"name": "John", "age": 30},

195

"conversation:456": {"topic": "weather", "turn_count": 5}

196

}

197

await storage.write(changes)

198

199

# Read data back

200

keys = ["user:123", "conversation:456"]

201

data = await storage.read(keys)

202

203

print(f"User data: {data.get('user:123')}")

204

print(f"Conversation data: {data.get('conversation:456')}")

205

206

# Delete data

207

await storage.delete(["user:123"])

208

```

209

210

### Custom Storage Implementation

211

212

```python

213

from botbuilder.core import Storage

214

import json

215

import os

216

217

class FileStorage(Storage):

218

def __init__(self, directory: str):

219

self.directory = directory

220

os.makedirs(directory, exist_ok=True)

221

222

async def read(self, keys):

223

items = {}

224

for key in keys:

225

file_path = os.path.join(self.directory, f"{key}.json")

226

if os.path.exists(file_path):

227

with open(file_path, 'r') as f:

228

items[key] = json.load(f)

229

return items

230

231

async def write(self, changes):

232

for key, value in changes.items():

233

file_path = os.path.join(self.directory, f"{key}.json")

234

with open(file_path, 'w') as f:

235

json.dump(value, f, indent=2)

236

237

async def delete(self, keys):

238

for key in keys:

239

file_path = os.path.join(self.directory, f"{key}.json")

240

if os.path.exists(file_path):

241

os.remove(file_path)

242

243

# Usage

244

file_storage = FileStorage("./bot_data")

245

conversation_state = ConversationState(file_storage)

246

user_state = UserState(file_storage)

247

```

248

249

### Storage with eTag Support

250

251

```python

252

from botbuilder.core import StoreItem, MemoryStorage

253

254

class UserProfile(StoreItem):

255

def __init__(self):

256

super().__init__()

257

self.name = None

258

self.email = None

259

self.preferences = {}

260

261

# Usage with eTag handling

262

storage = MemoryStorage()

263

264

# Create and store user profile

265

user_profile = UserProfile()

266

user_profile.name = "Alice"

267

user_profile.email = "alice@example.com"

268

269

await storage.write({"user:alice": user_profile})

270

271

# Read back with eTag preserved

272

data = await storage.read(["user:alice"])

273

retrieved_profile = data["user:alice"]

274

275

print(f"Profile eTag: {retrieved_profile.e_tag}")

276

277

# Modify and save (eTag will be updated automatically)

278

retrieved_profile.preferences["theme"] = "dark"

279

await storage.write({"user:alice": retrieved_profile})

280

```

281

282

### Queue Storage Usage

283

284

```python

285

from botbuilder.core import QueueStorage, Activity

286

287

# Create queue storage

288

queue_storage = QueueStorage()

289

290

# Queue some activities

291

activity1 = Activity(type="message", text="First message")

292

activity2 = Activity(type="message", text="Second message")

293

294

await queue_storage.queue_activity("pending", activity1)

295

await queue_storage.queue_activity("pending", activity2)

296

297

# Check queue length

298

length = await queue_storage.get_queue_length("pending")

299

print(f"Queue length: {length}")

300

301

# Process queue

302

while await queue_storage.get_queue_length("pending") > 0:

303

activity = await queue_storage.dequeue_activity("pending")

304

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

305

```

306

307

### Storage Error Handling

308

309

```python

310

async def safe_storage_operation(storage, key, data):

311

try:

312

await storage.write({key: data})

313

print(f"Successfully stored data for key: {key}")

314

except Exception as e:

315

print(f"Storage error for key {key}: {e}")

316

# Implement retry logic or fallback storage

317

await fallback_storage_operation(key, data)

318

319

async def fallback_storage_operation(key, data):

320

# Fallback to a different storage mechanism

321

fallback_storage = MemoryStorage()

322

await fallback_storage.write({key: data})

323

print(f"Data stored in fallback storage for key: {key}")

324

```

325

326

### Batch Storage Operations

327

328

```python

329

async def batch_user_update(storage, user_updates):

330

"""Update multiple users in a single storage operation."""

331

332

# Prepare batch changes

333

changes = {}

334

for user_id, update_data in user_updates.items():

335

key = f"user:{user_id}"

336

changes[key] = update_data

337

338

# Write all changes at once

339

await storage.write(changes)

340

print(f"Updated {len(changes)} users in batch")

341

342

# Usage

343

user_updates = {

344

"123": {"name": "John", "last_seen": "2023-01-01"},

345

"456": {"name": "Jane", "last_seen": "2023-01-02"},

346

"789": {"name": "Bob", "last_seen": "2023-01-03"}

347

}

348

349

await batch_user_update(storage, user_updates)

350

```

351

352

### Storage Key Management

353

354

```python

355

from botbuilder.core import sanitize_key

356

357

def create_storage_key(prefix: str, identifier: str, suffix: str = None):

358

"""Create a properly formatted storage key."""

359

parts = [prefix, identifier]

360

if suffix:

361

parts.append(suffix)

362

363

key = ":".join(parts)

364

return sanitize_key(key)

365

366

# Usage

367

user_key = create_storage_key("user", "john.doe@example.com")

368

conversation_key = create_storage_key("conversation", "teams-channel-123", "thread-456")

369

370

print(f"User key: {user_key}")

371

print(f"Conversation key: {conversation_key}")

372

```

373

374

## Types

375

376

```python { .api }

377

class StorageKeyFactory:

378

"""Factory for creating consistent storage keys."""

379

380

@staticmethod

381

def user_key(user_id: str):

382

"""Create user storage key."""

383

return f"user:{user_id}"

384

385

@staticmethod

386

def conversation_key(conversation_id: str):

387

"""Create conversation storage key."""

388

return f"conversation:{conversation_id}"

389

390

@staticmethod

391

def private_conversation_key(user_id: str, conversation_id: str):

392

"""Create private conversation storage key."""

393

return f"private:{user_id}:{conversation_id}"

394

```