Implement platform skill execution system and fix message formatting

Major features:
- Added platform skill execution architecture allowing agent to invoke
  platform-specific actions (delete posts, update rules, announcements)
- Agent now receives available platform skills and can execute them with
  proper authorization checks via constitution

Agent improvements:
- Added platform_skills parameter to process_request()
- New action type: execute_platform_skill with skill_name and skill_parameters
- Enhanced LLM prompts to distinguish between direct execution and skill execution
- Clearer JSON format specifications for different action types

Bot orchestration:
- Bot fetches platform skills and passes to agent
- Detects execute_platform_skill actions and calls platform.execute_skill()
- Handles skill execution results with proper error reporting

Mastodon platform:
- Implemented create_announcement skill with graceful API limitation handling
- Implemented update_instance_rules skill with graceful API limitation handling
- Both skills now acknowledge Mastodon API doesn't support these operations
  programmatically and provide direct admin interface links
- Implemented delete_status skill (working)
- All admin operations use direct API calls via __api_request

Message formatting fixes:
- Fixed message chunking to preserve line breaks and paragraph structure
- Split by paragraphs first, then lines, then words as last resort
- Removed debug logging for newline tracking

Documentation:
- Updated .gitignore to exclude bot.log and nohup.out

This implements the governance bot's ability to execute platform-specific
actions while respecting constitutional authority and handling API limitations
gracefully.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Nathan Schneider
2026-02-09 22:45:31 -07:00
parent 422f0859f4
commit a0785f09cf
5 changed files with 261 additions and 59 deletions

View File

@@ -587,20 +587,27 @@ class MastodonAdapter(PlatformAdapter):
}
def _update_instance_rules(self, params: Dict[str, Any]) -> Dict[str, Any]:
"""Update instance rules"""
# Note: This requires admin API access
# Implementation depends on Mastodon version and API availability
rules = params["rules"]
"""Update instance rules - web admin only"""
rules = params.get("rules", [])
# This would use admin API to update instance rules
# Exact implementation varies by Mastodon version
# Note: Mastodon's API does not provide endpoints for creating/updating rules.
# Rules must be managed through the web admin interface.
# See: https://docs.joinmastodon.org/methods/instance/
rules_text = "\n".join([f"- {rule}" for rule in rules])
return {
"success": True,
"message": f"Updated instance rules ({len(rules)} rules)",
"success": False,
"message": (
f"Proposed server rules:\n{rules_text}\n\n"
"Note: Mastodon's API does not support managing server rules programmatically. "
f"To update the server rules, please visit:\n"
f"{self.instance_url}/admin/server_settings/rules\n\n"
"You can add, edit, or remove rules through the admin interface."
),
"data": {"rules": rules},
"reversible": True,
"reverse_params": {"rules": "previous_rules"}, # Would need to store previous
"reversible": False,
"requires_manual_action": True,
}
def _update_instance_description(self, params: Dict[str, Any]) -> Dict[str, Any]:
@@ -649,23 +656,35 @@ class MastodonAdapter(PlatformAdapter):
}
def _create_announcement(self, params: Dict[str, Any]) -> Dict[str, Any]:
"""Create instance announcement"""
"""Create instance announcement - web admin only"""
text = params["text"]
starts_at = params.get("starts_at")
ends_at = params.get("ends_at")
announcement = self.client.admin_announcement_create(
text=text,
starts_at=starts_at,
ends_at=ends_at,
)
# Note: Mastodon's API does not provide endpoints for creating announcements.
# Announcements must be created through the web admin interface.
# See: https://docs.joinmastodon.org/methods/announcements/
timing_info = ""
if starts_at or ends_at:
timing_info = "\n\nTiming:"
if starts_at:
timing_info += f"\n- Start: {starts_at}"
if ends_at:
timing_info += f"\n- End: {ends_at}"
return {
"success": True,
"message": "Created announcement",
"data": {"announcement_id": announcement["id"], "text": text},
"reversible": True,
"reverse_params": {"announcement_id": announcement["id"]},
"success": False,
"message": (
f"Announcement text:\n{text}{timing_info}\n\n"
"Note: Mastodon's API does not support creating announcements programmatically. "
f"To post this announcement, please visit:\n"
f"{self.instance_url}/admin/announcements\n\n"
"Click 'New announcement', paste the text above, and publish it."
),
"data": {"text": text, "starts_at": starts_at, "ends_at": ends_at},
"reversible": False,
"requires_manual_action": True,
}
def _strip_markdown(self, text: str) -> str: