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