+21
-3
bsky.py
+21
-3
bsky.py
···
195
None: Failed with non-retryable error, move to errors directory
196
"""
197
try:
198
-
logger.info(f"Starting process_mention with notification_data type: {type(notification_data)}")
199
200
# Handle both dict and object inputs for backwards compatibility
201
if isinstance(notification_data, dict):
···
288
all_handles.update(extract_handles_from_data(thread.model_dump()))
289
unique_handles = list(all_handles)
290
291
-
logger.info(f"Found {len(unique_handles)} unique handles in thread: {unique_handles}")
292
293
# Attach user blocks before agent call
294
attached_handles = []
295
if unique_handles:
296
try:
297
-
logger.info(f"Attaching user blocks for handles: {unique_handles}")
298
attach_result = attach_user_blocks(unique_handles, void_agent)
299
attached_handles = unique_handles # Track successfully attached handles
300
logger.debug(f"Attach result: {attach_result}")
···
389
else:
390
logger.debug(f" {i}. {msg_type}: <no content>")
391
392
# Collect bluesky_reply tool calls
393
if hasattr(message, 'tool_call') and message.tool_call:
394
if message.tool_call.name == 'bluesky_reply':
···
195
None: Failed with non-retryable error, move to errors directory
196
"""
197
try:
198
+
logger.debug(f"Starting process_mention with notification_data type: {type(notification_data)}")
199
200
# Handle both dict and object inputs for backwards compatibility
201
if isinstance(notification_data, dict):
···
288
all_handles.update(extract_handles_from_data(thread.model_dump()))
289
unique_handles = list(all_handles)
290
291
+
logger.debug(f"Found {len(unique_handles)} unique handles in thread: {unique_handles}")
292
293
# Attach user blocks before agent call
294
attached_handles = []
295
if unique_handles:
296
try:
297
+
logger.debug(f"Attaching user blocks for handles: {unique_handles}")
298
attach_result = attach_user_blocks(unique_handles, void_agent)
299
attached_handles = unique_handles # Track successfully attached handles
300
logger.debug(f"Attach result: {attach_result}")
···
389
else:
390
logger.debug(f" {i}. {msg_type}: <no content>")
391
392
+
# Check for halt_activity tool call
393
+
if hasattr(message, 'tool_call') and message.tool_call:
394
+
if message.tool_call.name == 'halt_activity':
395
+
logger.info("🛑 HALT_ACTIVITY TOOL CALLED - TERMINATING BOT")
396
+
try:
397
+
args = json.loads(message.tool_call.arguments)
398
+
reason = args.get('reason', 'Agent requested halt')
399
+
logger.info(f"Halt reason: {reason}")
400
+
except:
401
+
logger.info("Halt reason: <unable to parse>")
402
+
403
+
# Export agent state before terminating
404
+
export_agent_state(CLIENT, void_agent)
405
+
406
+
# Exit the program
407
+
logger.info("=== BOT TERMINATED BY AGENT ===")
408
+
exit(0)
409
+
410
# Collect bluesky_reply tool calls
411
if hasattr(message, 'tool_call') and message.tool_call:
412
if message.tool_call.name == 'bluesky_reply':
+7
register_tools.py
+7
register_tools.py
···
15
from tools.feed import get_bluesky_feed, FeedArgs
16
from tools.blocks import attach_user_blocks, detach_user_blocks, AttachUserBlocksArgs, DetachUserBlocksArgs
17
from tools.reply import bluesky_reply, ReplyArgs
18
19
load_dotenv()
20
logging.basicConfig(level=logging.INFO)
···
59
"args_schema": ReplyArgs,
60
"description": "Reply indicator for the Letta agent (1-4 messages, each max 300 chars). Creates threaded replies.",
61
"tags": ["bluesky", "reply", "response"]
62
},
63
]
64
···
15
from tools.feed import get_bluesky_feed, FeedArgs
16
from tools.blocks import attach_user_blocks, detach_user_blocks, AttachUserBlocksArgs, DetachUserBlocksArgs
17
from tools.reply import bluesky_reply, ReplyArgs
18
+
from tools.halt import halt_activity, HaltArgs
19
20
load_dotenv()
21
logging.basicConfig(level=logging.INFO)
···
60
"args_schema": ReplyArgs,
61
"description": "Reply indicator for the Letta agent (1-4 messages, each max 300 chars). Creates threaded replies.",
62
"tags": ["bluesky", "reply", "response"]
63
+
},
64
+
{
65
+
"func": halt_activity,
66
+
"args_schema": HaltArgs,
67
+
"description": "Signal to halt all bot activity and terminate bsky.py",
68
+
"tags": ["control", "halt", "terminate"]
69
},
70
]
71
+26
tools/halt.py
+26
tools/halt.py
···
···
1
+
"""Halt tool for terminating bsky.py activity."""
2
+
from pydantic import BaseModel, Field
3
+
4
+
5
+
class HaltArgs(BaseModel):
6
+
reason: str = Field(
7
+
default="User requested halt",
8
+
description="Optional reason for halting activity"
9
+
)
10
+
11
+
12
+
def halt_activity(reason: str = "User requested halt") -> str:
13
+
"""
14
+
Signal to halt all bot activity and terminate bsky.py.
15
+
16
+
This tool allows the agent to request termination of the bot process.
17
+
The actual termination is handled externally by bsky.py when it detects
18
+
this tool being called.
19
+
20
+
Args:
21
+
reason: Optional reason for halting (default: "User requested halt")
22
+
23
+
Returns:
24
+
Halt signal message
25
+
"""
26
+
return f"Halting activity: {reason}"