-37
tools/blocks.py
-37
tools/blocks.py
···
1
1
"""Block management tools for user-specific memory blocks."""
2
2
from pydantic import BaseModel, Field
3
3
from typing import List, Dict, Any
4
-
import logging
5
4
6
5
def get_letta_client():
7
6
"""Get a Letta client using configuration."""
···
86
85
Returns:
87
86
String with attachment results for each handle
88
87
"""
89
-
logger = logging.getLogger(__name__)
90
88
91
89
handles = list(set(handles))
92
90
···
118
116
blocks = client.blocks.list(label=block_label)
119
117
if blocks and len(blocks) > 0:
120
118
block = blocks[0]
121
-
logger.debug(f"Found existing block: {block_label}")
122
119
123
120
# Double-check if this block is already attached by ID
124
121
if str(block.id) in current_block_ids:
···
130
127
value=f"# User: {handle}\n\nNo information about this user yet.",
131
128
limit=5000
132
129
)
133
-
logger.info(f"Created new block: {block_label}")
134
130
135
131
# Attach block atomically
136
132
try:
···
139
135
block_id=str(block.id)
140
136
)
141
137
results.append(f"✓ {handle}: Block attached")
142
-
logger.debug(f"Successfully attached block {block_label} to agent")
143
138
except Exception as attach_error:
144
139
# Check if it's a duplicate constraint error
145
140
error_str = str(attach_error)
146
141
if "duplicate key value violates unique constraint" in error_str and "unique_label_per_agent" in error_str:
147
142
# Block is already attached, possibly with this exact label
148
143
results.append(f"✓ {handle}: Already attached (verified)")
149
-
logger.debug(f"Block {block_label} was already attached (caught duplicate key error)")
150
144
else:
151
145
# Re-raise other errors
152
146
raise attach_error
153
147
154
148
except Exception as e:
155
149
results.append(f"✗ {handle}: Error - {str(e)}")
156
-
logger.error(f"Error processing block for {handle}: {e}")
157
150
158
151
return f"Attachment results:\n" + "\n".join(results)
159
152
160
153
except Exception as e:
161
-
logger.error(f"Error attaching user blocks: {e}")
162
154
raise Exception(f"Error attaching user blocks: {str(e)}")
163
155
164
156
···
173
165
Returns:
174
166
String with detachment results for each handle
175
167
"""
176
-
logger = logging.getLogger(__name__)
177
168
178
169
try:
179
170
client = get_letta_client()
···
200
191
block_id=block_label_to_id[block_label]
201
192
)
202
193
results.append(f"✓ {handle}: Detached")
203
-
logger.debug(f"Successfully detached block {block_label} from agent")
204
194
except Exception as e:
205
195
results.append(f"✗ {handle}: Error during detachment - {str(e)}")
206
-
logger.error(f"Error detaching block {block_label}: {e}")
207
196
else:
208
197
results.append(f"✗ {handle}: Not attached")
209
198
210
199
return f"Detachment results:\n" + "\n".join(results)
211
200
212
201
except Exception as e:
213
-
logger.error(f"Error detaching user blocks: {e}")
214
202
raise Exception(f"Error detaching user blocks: {str(e)}")
215
203
216
204
···
226
214
Returns:
227
215
String confirming the note was appended
228
216
"""
229
-
logger = logging.getLogger(__name__)
230
217
231
218
try:
232
219
client = get_letta_client()
···
249
236
block_id=str(block.id),
250
237
value=new_value
251
238
)
252
-
logger.info(f"Appended note to existing block: {block_label}")
253
239
return f"✓ Appended note to {handle}'s memory block"
254
240
255
241
else:
···
260
246
value=initial_value,
261
247
limit=5000
262
248
)
263
-
logger.info(f"Created new block with note: {block_label}")
264
249
265
250
# Check if block needs to be attached to agent
266
251
current_blocks = client.agents.blocks.list(agent_id=str(agent_state.id))
···
272
257
agent_id=str(agent_state.id),
273
258
block_id=str(block.id)
274
259
)
275
-
logger.info(f"Attached new block to agent: {block_label}")
276
260
return f"✓ Created and attached {handle}'s memory block with note"
277
261
else:
278
262
return f"✓ Created {handle}'s memory block with note"
279
263
280
264
except Exception as e:
281
-
logger.error(f"Error appending note to user block: {e}")
282
265
raise Exception(f"Error appending note to user block: {str(e)}")
283
266
284
267
···
295
278
Returns:
296
279
String confirming the text was replaced
297
280
"""
298
-
logger = logging.getLogger(__name__)
299
281
300
282
try:
301
283
client = get_letta_client()
···
325
307
block_id=str(block.id),
326
308
value=new_value
327
309
)
328
-
logger.info(f"Replaced text in block: {block_label}")
329
310
return f"✓ Replaced text in {handle}'s memory block"
330
311
331
312
except Exception as e:
332
-
logger.error(f"Error replacing text in user block: {e}")
333
313
raise Exception(f"Error replacing text in user block: {str(e)}")
334
314
335
315
···
345
325
Returns:
346
326
String confirming the content was set
347
327
"""
348
-
logger = logging.getLogger(__name__)
349
328
350
329
try:
351
330
client = get_letta_client()
···
364
343
block_id=str(block.id),
365
344
value=content
366
345
)
367
-
logger.info(f"Set content for existing block: {block_label}")
368
346
return f"✓ Set content for {handle}'s memory block"
369
347
370
348
else:
···
374
352
value=content,
375
353
limit=5000
376
354
)
377
-
logger.info(f"Created new block with content: {block_label}")
378
355
379
356
# Check if block needs to be attached to agent
380
357
current_blocks = client.agents.blocks.list(agent_id=str(agent_state.id))
···
386
363
agent_id=str(agent_state.id),
387
364
block_id=str(block.id)
388
365
)
389
-
logger.info(f"Attached new block to agent: {block_label}")
390
366
return f"✓ Created and attached {handle}'s memory block"
391
367
else:
392
368
return f"✓ Created {handle}'s memory block"
393
369
394
370
except Exception as e:
395
-
logger.error(f"Error setting user block content: {e}")
396
371
raise Exception(f"Error setting user block content: {str(e)}")
397
372
398
373
···
407
382
Returns:
408
383
String containing the user's memory block content
409
384
"""
410
-
logger = logging.getLogger(__name__)
411
385
412
386
try:
413
387
client = get_letta_client()
···
423
397
return f"No memory block found for user: {handle}"
424
398
425
399
block = blocks[0]
426
-
logger.info(f"Retrieved content for block: {block_label}")
427
400
428
401
return f"Memory block for {handle}:\n\n{block.value}"
429
402
430
403
except Exception as e:
431
-
logger.error(f"Error viewing user block: {e}")
432
404
raise Exception(f"Error viewing user block: {str(e)}")
433
405
434
406
···
445
417
Returns:
446
418
String with attachment results for each user ID
447
419
"""
448
-
logger = logging.getLogger(__name__)
449
420
450
421
user_ids = list(set(user_ids))
451
422
···
474
445
blocks = client.blocks.list(label=block_label)
475
446
if blocks and len(blocks) > 0:
476
447
block = blocks[0]
477
-
logger.debug(f"Found existing block: {block_label}")
478
448
else:
479
449
block = client.blocks.create(
480
450
label=block_label,
481
451
value=f"# X User: {user_id}\n\nNo information about this user yet.",
482
452
limit=5000
483
453
)
484
-
logger.info(f"Created new block: {block_label}")
485
454
486
455
# Attach block atomically
487
456
client.agents.blocks.attach(
···
494
463
495
464
except Exception as e:
496
465
results.append(f"✗ {user_id}: Error - {str(e)}")
497
-
logger.error(f"Error processing block for {user_id}: {e}")
498
466
499
467
return f"X user attachment results:\n" + "\n".join(results)
500
468
501
469
except Exception as e:
502
-
logger.error(f"Error attaching X user blocks: {e}")
503
470
raise Exception(f"Error attaching X user blocks: {str(e)}")
504
471
505
472
···
514
481
Returns:
515
482
String with detachment results for each user ID
516
483
"""
517
-
logger = logging.getLogger(__name__)
518
484
519
485
try:
520
486
client = get_letta_client()
···
539
505
block_id=block_label_to_id[block_label]
540
506
)
541
507
results.append(f"✓ {user_id}: Detached")
542
-
logger.debug(f"Successfully detached block {block_label} from agent")
543
508
except Exception as e:
544
509
results.append(f"✗ {user_id}: Error during detachment - {str(e)}")
545
-
logger.error(f"Error detaching block {block_label}: {e}")
546
510
else:
547
511
results.append(f"✗ {user_id}: Not attached")
548
512
549
513
return f"X user detachment results:\n" + "\n".join(results)
550
514
551
515
except Exception as e:
552
-
logger.error(f"Error detaching X user blocks: {e}")
553
516
raise Exception(f"Error detaching X user blocks: {str(e)}")
554
517
555
518
-6
tools/webpage.py
-6
tools/webpage.py
···
21
21
String containing the webpage content in markdown/text format
22
22
"""
23
23
import requests
24
-
import logging
25
-
26
-
logger = logging.getLogger(__name__)
27
24
28
25
try:
29
26
# Construct the Jina AI reader URL
···
33
30
response = requests.get(jina_url, timeout=30)
34
31
response.raise_for_status()
35
32
36
-
logger.info(f"Successfully fetched webpage: {url}")
37
33
return response.text
38
34
39
35
except requests.exceptions.RequestException as e:
40
-
logger.error(f"Error fetching webpage {url}: {e}")
41
36
raise Exception(f"Error fetching webpage: {str(e)}")
42
37
except Exception as e:
43
-
logger.error(f"Unexpected error fetching webpage {url}: {e}")
44
38
raise Exception(f"Unexpected error: {str(e)}")