diff --git a/TOOL_CHANGELOG.md b/TOOL_CHANGELOG.md new file mode 100644 --- /dev/null +++ b/TOOL_CHANGELOG.md @@ -0,0 +1,67 @@ +# Tool Changelog - Bluesky Reply Threading + +## Summary +The reply system has been simplified and improved with a new atomic approach for building reply threads. + +## Changes Made + +### ✅ NEW TOOL: `add_post_to_bluesky_reply_thread` +- **Purpose**: Add a single post to the current Bluesky reply thread atomically +- **Usage**: Call this tool multiple times to build a reply thread incrementally +- **Parameters**: + - `text` (required): Text content for the post (max 300 characters) + - `lang` (optional): Language code (defaults to "en-US") +- **Returns**: Confirmation that the post has been queued for the reply thread +- **Error Handling**: If text exceeds 300 characters, the post will be omitted from the thread and you may try again with shorter text + +### ❌ REMOVED TOOL: `bluesky_reply` +- This tool has been removed to eliminate confusion +- All reply functionality is now handled through the new atomic approach + +## How to Use the New System + +### Before (Old Way - NO LONGER AVAILABLE) +``` +bluesky_reply(["First reply", "Second reply", "Third reply"]) +``` + +### After (New Way - USE THIS) +``` +add_post_to_bluesky_reply_thread("First reply") +add_post_to_bluesky_reply_thread("Second reply") +add_post_to_bluesky_reply_thread("Third reply") +``` + +## Benefits of the New Approach + +1. **Atomic Operations**: Each post is handled individually, reducing the risk of entire thread failures +2. **Better Error Recovery**: If one post fails validation, others can still be posted +3. **Flexible Threading**: Build reply threads of any length without list construction +4. **Clearer Intent**: Each tool call has a single, clear purpose +5. **Handler-Managed State**: The bsky.py handler manages thread state and proper AT Protocol threading + +## Important Notes + +- The actual posting to Bluesky is handled by the bsky.py handler, not the tool itself +- Each call to `add_post_to_bluesky_reply_thread` queues a post for the current reply context +- Posts are validated for the 300-character limit before being queued +- Thread state and proper reply chaining is managed automatically by the handler +- Language defaults to "en-US" but can be specified per post if needed + +## Migration Guide + +If you were previously using `bluesky_reply`, simply replace it with multiple calls to `add_post_to_bluesky_reply_thread`: + +**Old approach:** +``` +bluesky_reply(["Hello!", "This is a threaded reply.", "Thanks for the mention!"]) +``` + +**New approach:** +``` +add_post_to_bluesky_reply_thread("Hello!") +add_post_to_bluesky_reply_thread("This is a threaded reply.") +add_post_to_bluesky_reply_thread("Thanks for the mention!") +``` + +This change makes the system more robust and easier to use while maintaining all the same functionality. \ No newline at end of file diff --git a/register_tools.py b/register_tools.py --- a/register_tools.py +++ b/register_tools.py @@ -14,8 +14,8 @@ from tools.post import create_new_bluesky_post, PostArgs from tools.feed import get_bluesky_feed, FeedArgs from tools.blocks import attach_user_blocks, detach_user_blocks, user_note_append, user_note_replace, user_note_set, user_note_view, AttachUserBlocksArgs, DetachUserBlocksArgs, UserNoteAppendArgs, UserNoteReplaceArgs, UserNoteSetArgs, UserNoteViewArgs -from tools.reply import bluesky_reply, ReplyArgs from tools.halt import halt_activity, HaltArgs +from tools.thread import add_post_to_bluesky_reply_thread, ReplyThreadPostArgs load_dotenv() logging.basicConfig(level=logging.INFO) @@ -80,16 +80,16 @@ "tags": ["memory", "blocks", "user", "view"] }, { - "func": bluesky_reply, - "args_schema": ReplyArgs, - "description": "Reply indicator for the Letta agent (1-4 messages, each max 300 chars). Creates threaded replies.", - "tags": ["bluesky", "reply", "response"] - }, - { "func": halt_activity, "args_schema": HaltArgs, "description": "Signal to halt all bot activity and terminate bsky.py", "tags": ["control", "halt", "terminate"] + }, + { + "func": add_post_to_bluesky_reply_thread, + "args_schema": ReplyThreadPostArgs, + "description": "Add a single post to the current Bluesky reply thread atomically", + "tags": ["bluesky", "reply", "thread", "atomic"] }, ] diff --git a/tools/thread.py b/tools/thread.py new file mode 100644 --- /dev/null +++ b/tools/thread.py @@ -0,0 +1,50 @@ +"""Thread tool for adding posts to Bluesky threads atomically.""" +from typing import Optional +from pydantic import BaseModel, Field, validator + + +class ReplyThreadPostArgs(BaseModel): + text: str = Field( + ..., + description="Text content for the post (max 300 characters)" + ) + lang: Optional[str] = Field( + default="en-US", + description="Language code for the post (e.g., 'en-US', 'es', 'ja', 'th'). Defaults to 'en-US'" + ) + + @validator('text') + def validate_text_length(cls, v): + if len(v) > 300: + raise ValueError(f"Text exceeds 300 character limit (current: {len(v)} characters)") + return v + + +def add_post_to_bluesky_reply_thread(text: str, lang: str = "en-US") -> str: + """ + Add a single post to the current Bluesky reply thread. This tool indicates to the handler + that it should add this post to the ongoing reply thread context when responding to a notification. + + This is distinct from bluesky_reply which handles the complete reply process. Use this tool + when you want to build a reply thread incrementally, adding posts one at a time. + + This is an atomic operation - each call adds exactly one post. The handler (bsky.py) + manages the thread state and ensures proper threading when multiple posts are queued. + + Args: + text: Text content for the post (max 300 characters) + lang: Language code for the post (e.g., 'en-US', 'es', 'ja', 'th'). Defaults to 'en-US' + + Returns: + Confirmation message that the post has been queued for the reply thread + + Raises: + Exception: If text exceeds character limit. On failure, the post will be omitted + from the reply thread and the agent may try again with corrected text. + """ + # Validate input + if len(text) > 300: + raise Exception(f"Text exceeds 300 character limit (current: {len(text)} characters). This post will be omitted from the thread. You may try again with shorter text.") + + # Return confirmation - the actual posting will be handled by bsky.py + return f"Post queued for reply thread: {text[:50]}{'...' if len(text) > 50 else ''} (Language: {lang})" \ No newline at end of file