Enhance tool response handling and parsing; update tool markers configuration and usage guidelines
This commit is contained in:
@@ -255,17 +255,18 @@ class APIManager:
|
||||
}
|
||||
)
|
||||
|
||||
# Import tools
|
||||
# Import tools and tool response parser
|
||||
from .handlers.function_tools import TOOLS, parse_tool_response
|
||||
|
||||
# Prepare request data
|
||||
# Prepare request data with OpenAI function calling format
|
||||
data = {
|
||||
"model": params["model"],
|
||||
"messages": messages,
|
||||
"temperature": params["temperature"],
|
||||
"max_tokens": params["max_tokens"],
|
||||
"stream": False, # Disable streaming for all requests
|
||||
"tools": TOOLS # Add available tools
|
||||
"tools": TOOLS, # Add function definitions
|
||||
"tool_choice": "auto" # Let model decide when to use tools
|
||||
}
|
||||
logger.debug(
|
||||
"API Request Details:\n"
|
||||
@@ -321,27 +322,36 @@ class APIManager:
|
||||
# Process the response
|
||||
try:
|
||||
json_response = await response.json()
|
||||
if json_response.get("choices"):
|
||||
choice = json_response["choices"][0]
|
||||
if "message" in choice:
|
||||
message = choice["message"]
|
||||
|
||||
# Check for tool calls first
|
||||
if "tool_calls" in message:
|
||||
tool_response = parse_tool_response(json_response)
|
||||
if tool_response:
|
||||
return True, json.dumps(tool_response)
|
||||
|
||||
# Fall back to regular content
|
||||
content = message.get("content", "")
|
||||
if content and content.strip():
|
||||
return True, content
|
||||
|
||||
# Log if no valid response found
|
||||
logger.error("No valid content or tool calls in response")
|
||||
logger.debug(f"Response headers: {response.headers}")
|
||||
logger.debug(f"Response status: {response.status}")
|
||||
return False, None
|
||||
logger.debug(f"Raw API response: {json_response}")
|
||||
|
||||
if not json_response.get("choices"):
|
||||
logger.error("No choices in response")
|
||||
return False, None
|
||||
|
||||
choice = json_response["choices"][0]
|
||||
if not choice.get("message"):
|
||||
logger.error("No message in choice")
|
||||
return False, None
|
||||
|
||||
message = choice["message"]
|
||||
|
||||
# Check for tool calls first
|
||||
if message.get("tool_calls"):
|
||||
tool_data = parse_tool_response(json_response)
|
||||
if tool_data:
|
||||
logger.debug(f"Found tool calls: {tool_data}")
|
||||
return True, json.dumps(tool_data)
|
||||
|
||||
# Fall back to regular content if present
|
||||
content = message.get("content", "").strip()
|
||||
if content:
|
||||
logger.debug(f"Found content: {content[:100]}")
|
||||
return True, content
|
||||
|
||||
# No valid content or tool calls
|
||||
logger.error("No valid content or tool calls found")
|
||||
logger.debug(f"Full message: {message}")
|
||||
return False, None
|
||||
except json.JSONDecodeError as e:
|
||||
logger.error(f"Failed to decode response: {e}")
|
||||
return False, None
|
||||
|
||||
@@ -94,7 +94,7 @@ def function_to_tool_call(function_name: str, arguments: Dict[str, Any]) -> Dict
|
||||
}
|
||||
|
||||
def parse_tool_response(response: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""Parse an API response looking for tool calls."""
|
||||
"""Parse an API response looking for function calls in tool_calls format."""
|
||||
if not response or "choices" not in response:
|
||||
return {}
|
||||
|
||||
@@ -109,9 +109,11 @@ def parse_tool_response(response: Dict[str, Any]) -> Dict[str, Any]:
|
||||
tool_calls = []
|
||||
for tool_call in message["tool_calls"]:
|
||||
if tool_call["type"] == "function":
|
||||
tool_calls.append(function_to_tool_call(
|
||||
tool_call["function"]["name"],
|
||||
tool_call["function"]["arguments"]
|
||||
))
|
||||
# Extract function name and arguments
|
||||
function_call = {
|
||||
"name": tool_call["function"]["name"],
|
||||
"arguments": json.loads(tool_call["function"]["arguments"])
|
||||
}
|
||||
tool_calls.append(function_call)
|
||||
|
||||
return {"tool_calls": tool_calls} if tool_calls else {}
|
||||
@@ -2,6 +2,7 @@
|
||||
"""Tool execution and response handling logic."""
|
||||
|
||||
import re
|
||||
import json
|
||||
from typing import Dict, Any, Optional, List, Tuple
|
||||
from discord import TextChannel, Message, utils, Embed, PartialEmoji
|
||||
|
||||
@@ -15,6 +16,129 @@ class ToolHandler:
|
||||
self.bot = bot
|
||||
self.mentioned_users = {} # Map usernames to their mention formats
|
||||
|
||||
def _extract_json_data(self, json_str: str) -> Tuple[str, Dict[str, Any]]:
|
||||
"""Extract tool name and arguments from various JSON formats."""
|
||||
# Try full JSON parsing first
|
||||
try:
|
||||
data = json.loads(json_str)
|
||||
name = data.get("name", "")
|
||||
args = data.get("parameters") or data.get("arguments") or {}
|
||||
return name, args
|
||||
except json.JSONDecodeError:
|
||||
pass
|
||||
|
||||
# Fallback to regex extraction
|
||||
try:
|
||||
name_match = re.search(r'"name":\s*"([^"]+)"', json_str)
|
||||
if not name_match:
|
||||
return "", {}
|
||||
|
||||
name = name_match.group(1)
|
||||
|
||||
# Try to extract parameters/arguments
|
||||
args_match = re.search(r'"(?:parameters|arguments)":\s*({[^}]+})', json_str)
|
||||
if args_match:
|
||||
try:
|
||||
args = json.loads(args_match.group(1))
|
||||
except json.JSONDecodeError:
|
||||
args = {}
|
||||
else:
|
||||
args = {}
|
||||
|
||||
return name, args
|
||||
except Exception as e:
|
||||
logger.error(f"Error extracting JSON data: {e}")
|
||||
return "", {}
|
||||
|
||||
def _convert_to_natural_format(self, tool_name: str, args: Dict[str, Any]) -> str:
|
||||
"""Convert tool call data to natural language format."""
|
||||
try:
|
||||
if tool_name == "mention_user" and "name" in args:
|
||||
return f"[TOOL:mention]@{args['name']}[/TOOL]"
|
||||
elif tool_name == "add_reaction" and "emoji" in args:
|
||||
return f"[TOOL:reaction]{args['emoji']}[/TOOL]"
|
||||
elif tool_name == "create_embed":
|
||||
title = args.get("title", "")
|
||||
desc = args.get("description", "")
|
||||
content = f"{title}\n{desc}" if title and desc else title or desc
|
||||
return f"[TOOL:embed]\n{content}\n[/TOOL]"
|
||||
elif tool_name == "create_thread":
|
||||
name = args.get("name", args.get("topic", ""))
|
||||
if name:
|
||||
return f"[TOOL:thread]{name}[/TOOL]"
|
||||
except Exception as e:
|
||||
logger.error(f"Error converting to natural format: {e}")
|
||||
return ""
|
||||
|
||||
def parse_tool_calls(
|
||||
self,
|
||||
response: str,
|
||||
message_id: Optional[int] = None,
|
||||
channel_id: Optional[int] = None,
|
||||
) -> Tuple[List[Tuple[str, Dict[str, Any]]], str]:
|
||||
"""Parse all tool calls from a response string."""
|
||||
try:
|
||||
# Initialize variables
|
||||
tool_calls = []
|
||||
final_response = response
|
||||
|
||||
# Find potential JSON tool calls
|
||||
pattern = r'\{(?:[^{}]|{[^{}]*})*\}' # Matches JSON objects, including nested ones
|
||||
matches = list(re.finditer(pattern, response))
|
||||
|
||||
for match in matches:
|
||||
try:
|
||||
json_str = match.group(0)
|
||||
tool_name, args = self._extract_json_data(json_str)
|
||||
|
||||
if not tool_name:
|
||||
continue
|
||||
|
||||
# Add channel and message IDs where needed
|
||||
if tool_name in ["add_reaction", "create_thread"]:
|
||||
args["channel_id"] = channel_id
|
||||
args["message_id"] = message_id
|
||||
|
||||
# Add to tool calls
|
||||
tool_calls.append((tool_name, args))
|
||||
|
||||
# Convert to natural format in the response
|
||||
natural_format = self._convert_to_natural_format(tool_name, args)
|
||||
if natural_format:
|
||||
final_response = final_response.replace(json_str, natural_format)
|
||||
else:
|
||||
final_response = final_response.replace(json_str, "")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error processing tool call: {e}")
|
||||
continue
|
||||
|
||||
# Clean up the response
|
||||
final_response = "\n".join(line for line in final_response.split("\n") if line.strip())
|
||||
|
||||
# Add default message if response is empty
|
||||
if not final_response and tool_calls:
|
||||
action_map = {
|
||||
"create_thread": "Starting a new discussion thread...",
|
||||
"add_reaction": "Adding reaction...",
|
||||
"create_embed": "Creating embed...",
|
||||
"mention_user": "Mentioning user..."
|
||||
}
|
||||
|
||||
for tool_name, _ in tool_calls:
|
||||
if tool_name in action_map:
|
||||
final_response = action_map[tool_name]
|
||||
break
|
||||
|
||||
if not final_response:
|
||||
final_response = "Processing your request..."
|
||||
|
||||
return tool_calls, final_response, self.mentioned_users
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error parsing tool calls: {e}")
|
||||
return [], response, {}
|
||||
|
||||
async def find_user_by_name(
|
||||
self, name: str, guild_id: Optional[int] = None
|
||||
) -> Optional[str]:
|
||||
@@ -105,18 +229,15 @@ class ToolHandler:
|
||||
if guild_emoji:
|
||||
await message.add_reaction(guild_emoji)
|
||||
else:
|
||||
logger.warning(f"Tool Use - Add Reaction: Could not find emoji '{emoji_name}' in guild emojis")
|
||||
logger.warning(f"Could not find emoji '{emoji_name}' in guild emojis")
|
||||
else:
|
||||
logger.warning(f"Tool Use - Add Reaction: Invalid emoji format '{emoji}' - must be Unicode emoji, custom emoji (<:name:id>), or standard emoji (:name:)")
|
||||
logger.warning(f"Invalid emoji format '{emoji}' - must be Unicode emoji, custom emoji (<:name:id>), or standard emoji (:name:)")
|
||||
return
|
||||
|
||||
logger.info(f"Tool Use - Add Reaction: Successfully added '{emoji}' to message {message_id}")
|
||||
logger.info(f"Successfully added '{emoji}' to message {message_id}")
|
||||
except Exception as e:
|
||||
logger.error(f"Tool Use - Add Reaction: Failed to add reaction: {e}")
|
||||
logger.error(f"Failed to add reaction: {e}")
|
||||
|
||||
logger.info(
|
||||
f"Tool Use - Add Reaction: Successfully added '{emoji}' to message {message_id}"
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"Tool Use - Add Reaction: Failed to add reaction: {e}")
|
||||
|
||||
@@ -167,22 +288,18 @@ class ToolHandler:
|
||||
|
||||
try:
|
||||
# Clean and format thread name
|
||||
# Remove mentions and clean up text
|
||||
formatted_name = re.sub(r'<@!?\d+>', '', name) # Remove mentions
|
||||
formatted_name = re.sub(r'\s+', ' ', formatted_name) # Normalize whitespace
|
||||
formatted_name = formatted_name.strip()
|
||||
|
||||
# Extract core topic
|
||||
# Look for key comparison or topic patterns
|
||||
# Extract core topic and format name
|
||||
if "vs" in formatted_name.lower() or "versus" in formatted_name.lower():
|
||||
# Extract the comparison parts
|
||||
parts = re.split(r'\bvs\.?\b|\bversus\b', formatted_name, flags=re.IGNORECASE)
|
||||
if len(parts) >= 2:
|
||||
formatted_name = f"{parts[0].strip()} vs {parts[1].strip()}"
|
||||
if not formatted_name.lower().endswith(" debate"):
|
||||
formatted_name += " debate"
|
||||
elif "overrated" in formatted_name.lower() or "underrated" in formatted_name.lower():
|
||||
# Extract just the coaster name and rating type
|
||||
match = re.search(r'(.*?)\b(over|under)rated\b', formatted_name, re.IGNORECASE)
|
||||
if match:
|
||||
formatted_name = f"{match.group(1).strip()} {match.group(2)}rated discussion"
|
||||
@@ -202,7 +319,7 @@ class ToolHandler:
|
||||
auto_archive_duration=1440 # 24 hours
|
||||
)
|
||||
if thread:
|
||||
logger.info(f"Tool Use - Create Thread: Successfully created thread '{formatted_name}' from message")
|
||||
logger.info(f"Successfully created thread '{formatted_name}' from message")
|
||||
return thread
|
||||
else:
|
||||
thread = await channel.create_thread(
|
||||
@@ -211,154 +328,16 @@ class ToolHandler:
|
||||
auto_archive_duration=1440 # 24 hours
|
||||
)
|
||||
if thread:
|
||||
logger.info(f"Tool Use - Create Thread: Successfully created thread '{formatted_name}'")
|
||||
logger.info(f"Successfully created thread '{formatted_name}'")
|
||||
return thread
|
||||
|
||||
logger.error("Tool Use - Create Thread: Failed to create thread - no thread object returned")
|
||||
logger.error("Failed to create thread - no thread object returned")
|
||||
return None
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Tool Use - Create Thread: Failed to create thread: {e}")
|
||||
logger.error(f"Failed to create thread: {e}")
|
||||
return None
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Tool Use - Create Thread: Failed to create thread: {e}")
|
||||
|
||||
def validate_tool_response(self, response: str) -> bool:
|
||||
"""Validate proper tool marker closure.
|
||||
|
||||
Args:
|
||||
response: The response string to validate
|
||||
|
||||
Returns:
|
||||
bool: True if all tool markers are properly closed, False otherwise
|
||||
"""
|
||||
from .tools import TOOL_MARKERS
|
||||
try:
|
||||
stack = []
|
||||
|
||||
# Find all tool markers
|
||||
pattern = f"{re.escape(TOOL_MARKERS['start'])}\\w+\\]|{re.escape(TOOL_MARKERS['end'])}"
|
||||
markers = re.finditer(pattern, response)
|
||||
|
||||
for match in markers:
|
||||
marker = match.group(0)
|
||||
if TOOL_MARKERS['end'] in marker:
|
||||
if not stack:
|
||||
logger.warning(f"Tool Use - Validate: Found end marker without matching start: {marker}")
|
||||
return False
|
||||
start_marker = stack.pop()
|
||||
logger.debug(f"Tool Use - Validate: Matched {start_marker} with {marker}")
|
||||
else:
|
||||
stack.append(marker)
|
||||
logger.debug(f"Tool Use - Validate: Found start marker: {marker}")
|
||||
|
||||
if stack:
|
||||
logger.warning(f"Tool Use - Validate: Unclosed tool markers found: {stack}")
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Tool Use - Validate: Error validating tool markers: {e}")
|
||||
return False
|
||||
|
||||
def parse_tool_calls(
|
||||
self,
|
||||
response: str,
|
||||
message_id: Optional[int] = None,
|
||||
channel_id: Optional[int] = None,
|
||||
) -> Tuple[List[Tuple[str, Dict[str, Any]]], str]:
|
||||
"""Parse all tool calls from a response string.
|
||||
|
||||
Args:
|
||||
response: The response string to parse
|
||||
message_id: Optional ID of the message being responded to
|
||||
channel_id: Optional ID of the channel the message is in
|
||||
"""
|
||||
from .tools import TOOL_MARKERS
|
||||
|
||||
try:
|
||||
# Validate tool markers first
|
||||
if not self.validate_tool_response(response):
|
||||
logger.warning("Tool Use - Parse: Invalid tool marker structure, skipping tool parsing")
|
||||
return [], response, {}
|
||||
|
||||
tool_calls = []
|
||||
final_response = response
|
||||
|
||||
# Process tool markers in order of appearance
|
||||
for tool_type, markers in TOOL_MARKERS["patterns"].items():
|
||||
pattern = f"{re.escape(markers['start'])}(.*?){re.escape(markers['end'])}"
|
||||
matches = list(re.finditer(pattern, response, re.DOTALL))
|
||||
|
||||
for match in matches:
|
||||
content = match.group(1).strip()
|
||||
if not content:
|
||||
continue
|
||||
|
||||
logger.info(f"Tool Use - Parse: Found {tool_type} tool usage: {content[:50]}...")
|
||||
|
||||
# Process based on tool type
|
||||
if tool_type == "mention":
|
||||
# Extract username from @mention
|
||||
if "@" in content:
|
||||
name = re.search(r"@(\w+(?:\s+\w+)*)", content)
|
||||
if name:
|
||||
name = name.group(1).strip()
|
||||
tool_calls.append(("find_user", {"name": name}))
|
||||
logger.info(f"Tool Use - Parse: Adding find_user tool call for '{name}'")
|
||||
|
||||
elif tool_type == "reaction":
|
||||
# Process emoji reactions
|
||||
emoji_pattern = r'([😀-🙏🌀-🗿]|<a?:[a-zA-Z0-9_]+:\d+>|:[a-zA-Z0-9_]+:)'
|
||||
emoji_matches = re.finditer(emoji_pattern, content)
|
||||
for emoji_match in emoji_matches:
|
||||
emoji = emoji_match.group(1)
|
||||
if emoji.strip():
|
||||
tool_calls.append(("add_reaction", {
|
||||
"emoji": emoji,
|
||||
"message_id": message_id,
|
||||
"channel_id": channel_id
|
||||
}))
|
||||
logger.info(f"Tool Use - Parse: Adding add_reaction tool call for emoji '{emoji}'")
|
||||
|
||||
elif tool_type == "embed":
|
||||
# Process embed content
|
||||
lines = content.strip().split("\n")
|
||||
if lines:
|
||||
title = lines[0]
|
||||
description = "\n".join(lines[1:]) if len(lines) > 1 else ""
|
||||
tool_calls.append(("create_embed", {
|
||||
"title": title,
|
||||
"description": description,
|
||||
"color": 0xFF0000 # Default red color
|
||||
}))
|
||||
logger.info(f"Tool Use - Parse: Adding create_embed tool call with title '{title}'")
|
||||
|
||||
elif tool_type == "thread":
|
||||
# Process thread creation
|
||||
thread_name = content.strip()
|
||||
if thread_name:
|
||||
tool_calls.append(("create_thread", {
|
||||
"channel_id": channel_id,
|
||||
"name": thread_name,
|
||||
"message_id": message_id
|
||||
}))
|
||||
logger.info(f"Tool Use - Parse: Adding create_thread tool call for '{thread_name}'")
|
||||
|
||||
# Remove the tool marker and its content from the final response
|
||||
final_response = final_response.replace(match.group(0), "")
|
||||
|
||||
# Clean up the final response
|
||||
final_response = "\n".join(line for line in final_response.split("\n") if line.strip())
|
||||
|
||||
# Log summary of detected tools
|
||||
if tool_calls:
|
||||
logger.info(f"Tool Use - Parse: Detected {len(tool_calls)} tool calls: {[call[0] for call in tool_calls]}")
|
||||
|
||||
return tool_calls, final_response, self.mentioned_users
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Tool Use - Parse: Error parsing tool calls: {e}")
|
||||
# Return empty tool calls but preserve original response
|
||||
return [], response, {}
|
||||
return None
|
||||
|
||||
@@ -1,25 +1,32 @@
|
||||
"""Tools available for LLM use and their documentation."""
|
||||
|
||||
# Tool Markers Configuration
|
||||
# Tool Format Configuration
|
||||
TOOL_MARKERS = {
|
||||
"start": "[TOOL:",
|
||||
"end": "[/TOOL]",
|
||||
"patterns": {
|
||||
"mention": {
|
||||
"start": "[TOOL:mention]",
|
||||
"end": "[/TOOL]"
|
||||
},
|
||||
"reaction": {
|
||||
"start": "[TOOL:reaction]",
|
||||
"end": "[/TOOL]"
|
||||
},
|
||||
"embed": {
|
||||
"start": "[TOOL:embed]",
|
||||
"end": "[/TOOL]"
|
||||
},
|
||||
"thread": {
|
||||
"start": "[TOOL:thread]",
|
||||
"end": "[/TOOL]"
|
||||
"json": {
|
||||
"start": "<tool_call>",
|
||||
"end": "</tool_call>",
|
||||
"format": "{\"name\": \"%s\", \"arguments\": %s}"
|
||||
},
|
||||
"natural": {
|
||||
"start": "[TOOL:",
|
||||
"end": "[/TOOL]",
|
||||
"patterns": {
|
||||
"mention_user": {
|
||||
"start": "[TOOL:mention]",
|
||||
"end": "[/TOOL]"
|
||||
},
|
||||
"add_reaction": {
|
||||
"start": "[TOOL:reaction]",
|
||||
"end": "[/TOOL]"
|
||||
},
|
||||
"create_embed": {
|
||||
"start": "[TOOL:embed]",
|
||||
"end": "[/TOOL]"
|
||||
},
|
||||
"create_thread": {
|
||||
"start": "[TOOL:thread]",
|
||||
"end": "[/TOOL]"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,8 +38,8 @@ TOOLS = {
|
||||
"parameters": {
|
||||
"name": "The username or nickname to mention",
|
||||
},
|
||||
"example": "[TOOL:mention]@username[/TOOL]",
|
||||
"usage": "Wrap mentions with [TOOL:mention] markers: [TOOL:mention]@john[/TOOL]"
|
||||
"example": "Hey [TOOL:mention]@username[/TOOL], what do you think?",
|
||||
"usage": "Use [TOOL:mention] to mention users: [TOOL:mention]@john[/TOOL]"
|
||||
},
|
||||
|
||||
"add_reaction": {
|
||||
@@ -40,8 +47,8 @@ TOOLS = {
|
||||
"parameters": {
|
||||
"emoji": "The emoji to add as a reaction. Can be Unicode emoji, custom emoji (<:name:id>), or standard emoji (:name:)"
|
||||
},
|
||||
"example": "[TOOL:reaction]😊[/TOOL] or [TOOL:reaction]:smile:[/TOOL]",
|
||||
"usage": "Wrap emojis with [TOOL:reaction] markers"
|
||||
"example": "That's awesome! [TOOL:reaction]👍[/TOOL]",
|
||||
"usage": "Use [TOOL:reaction] for reactions: [TOOL:reaction]😊[/TOOL] or [TOOL:reaction]:smile:[/TOOL]"
|
||||
},
|
||||
|
||||
"create_embed": {
|
||||
@@ -53,12 +60,12 @@ TOOLS = {
|
||||
},
|
||||
"example": """
|
||||
[TOOL:embed]
|
||||
Title Goes Here
|
||||
This is the description content
|
||||
It can span multiple lines
|
||||
Poll Results
|
||||
First place: X
|
||||
Second place: Y
|
||||
[/TOOL]
|
||||
""",
|
||||
"usage": "Wrap embed content with [TOOL:embed] markers"
|
||||
"usage": "Use [TOOL:embed] for embeds, with title on first line and content on following lines"
|
||||
},
|
||||
|
||||
"create_thread": {
|
||||
@@ -67,36 +74,53 @@ TOOLS = {
|
||||
"name": "The name/topic for the thread",
|
||||
"message_id": "Optional ID of message to create thread from"
|
||||
},
|
||||
"example": "[TOOL:thread]Let's discuss X vs Y[/TOOL] or [TOOL:thread]This coaster is overrated[/TOOL]",
|
||||
"usage": "Wrap thread topics with [TOOL:thread] markers"
|
||||
"example": "[TOOL:thread]Let's discuss X vs Y[/TOOL]",
|
||||
"usage": "Use [TOOL:thread] to create discussion threads: [TOOL:thread]Is this coaster overrated?[/TOOL]"
|
||||
}
|
||||
}
|
||||
|
||||
# Tool Usage Guidelines
|
||||
USAGE_GUIDELINES = """
|
||||
Tools must be used with explicit markers in conversation:
|
||||
Tools must be used with [TOOL:type] markers in natural language:
|
||||
|
||||
1. To mention a user:
|
||||
Example: "Hey [TOOL:mention]@john[/TOOL], what do you think?"
|
||||
[TOOL:mention]@username[/TOOL]
|
||||
Examples:
|
||||
- "Hey [TOOL:mention]@john[/TOOL], what's up?"
|
||||
- "[TOOL:mention]@sarah[/TOOL] check this out!"
|
||||
|
||||
2. To add reactions:
|
||||
Example: "That's a great point! [TOOL:reaction]👍[/TOOL]"
|
||||
[TOOL:reaction]emoji[/TOOL]
|
||||
Examples:
|
||||
- "That's awesome! [TOOL:reaction]👍[/TOOL]"
|
||||
- "LOL [TOOL:reaction]🤣[/TOOL]"
|
||||
- "Nice! [TOOL:reaction]:heart:[/TOOL]"
|
||||
|
||||
3. To create embeds:
|
||||
[TOOL:embed]
|
||||
Title goes here
|
||||
Content starts here
|
||||
Can have multiple lines
|
||||
[/TOOL]
|
||||
Example:
|
||||
[TOOL:embed]
|
||||
Poll Results
|
||||
First place: X
|
||||
Second place: Y
|
||||
Today's Poll
|
||||
1. First option
|
||||
2. Second option
|
||||
[/TOOL]
|
||||
|
||||
4. To create threads:
|
||||
[TOOL:thread]thread topic[/TOOL]
|
||||
Examples:
|
||||
- [TOOL:thread]Let's compare X vs Y[/TOOL]
|
||||
- [TOOL:thread]Is this coaster overrated?[/TOOL]
|
||||
- [TOOL:thread]Time for a safety discussion[/TOOL]
|
||||
- "[TOOL:thread]Let's compare X vs Y[/TOOL]"
|
||||
- "[TOOL:thread]Is this ride overrated?[/TOOL]"
|
||||
- "[TOOL:thread]Safety discussion[/TOOL]"
|
||||
|
||||
Note: Always ensure tool markers are properly closed with their corresponding end tags.
|
||||
Important Rules:
|
||||
1. ALWAYS use [TOOL:type]...[/TOOL] format
|
||||
2. Include tools naturally in your sentences
|
||||
3. Make sure to close all tool tags properly
|
||||
4. Never use any other format (no JSON, no <>)
|
||||
"""
|
||||
|
||||
# Error Messages
|
||||
|
||||
Reference in New Issue
Block a user