feature/web-search-and-cron-improvements #2

Merged
tanyar09 merged 12 commits from feature/web-search-and-cron-improvements into feature/cleanup-providers-llama-only 2026-03-06 13:20:19 -05:00
3 changed files with 41 additions and 7 deletions
Showing only changes of commit 6364a195c5 - Show all commits

View File

@ -252,6 +252,7 @@ class CalendarConfig(Base):
token_file: str = "" # Path to store OAuth2 token (default: ~/.nanobot/calendar_token.json) token_file: str = "" # Path to store OAuth2 token (default: ~/.nanobot/calendar_token.json)
calendar_id: str = "primary" # Calendar ID to use (default: primary calendar) calendar_id: str = "primary" # Calendar ID to use (default: primary calendar)
auto_schedule_from_email: bool = True # Automatically schedule meetings from emails auto_schedule_from_email: bool = True # Automatically schedule meetings from emails
timezone: str = "UTC" # Timezone for parsing times (e.g., "America/New_York", "Europe/London", "UTC")
class ExecToolConfig(Base): class ExecToolConfig(Base):

View File

@ -62,22 +62,37 @@ class CustomProvider(LLMProvider):
# If no structured tool calls, try to parse from content (Ollama sometimes returns JSON in content) # If no structured tool calls, try to parse from content (Ollama sometimes returns JSON in content)
# Only parse if content looks like it contains a tool call JSON (to avoid false positives) # Only parse if content looks like it contains a tool call JSON (to avoid false positives)
content = msg.content or "" content = msg.content or ""
if not tool_calls and content and '"name"' in content and '"parameters"' in content: # Check for standard format: {"name": "...", "parameters": {...}}
has_standard_format = '"name"' in content and '"parameters"' in content
# Check for calendar tool format: {"action": "...", ...}
has_calendar_format = '"action"' in content and ("calendar" in content.lower() or any(action in content for action in ["list_events", "create_event", "update_event", "delete_event"]))
if not tool_calls and content and (has_standard_format or has_calendar_format):
import re import re
# Look for JSON tool call patterns: {"name": "exec", "parameters": {...}} # Look for JSON tool call patterns: {"name": "exec", "parameters": {...}} or {"action": "list_events", ...}
# Find complete JSON objects by matching braces # Find complete JSON objects by matching braces
pattern = r'\{\s*"name"\s*:\s*"(\w+)"' # Try "action" pattern first (for calendar tool), then "name" pattern
patterns = [
(r'\{\s*"action"\s*:\s*"(\w+)"', "action"), # Calendar tool format
(r'\{\s*"name"\s*:\s*"(\w+)"', "name"), # Standard format
]
start_pos = 0 start_pos = 0
max_iterations = 5 # Safety limit max_iterations = 10 # Increased for multiple patterns
iteration = 0 iteration = 0
while iteration < max_iterations: while iteration < max_iterations:
iteration += 1 iteration += 1
match = re.search(pattern, content[start_pos:]) match = None
pattern_type = None
for pattern, ptype in patterns:
match = re.search(pattern, content[start_pos:])
if match:
pattern_type = ptype
break
if not match: if not match:
break break
json_start = start_pos + match.start() json_start = start_pos + match.start()
name = match.group(1) key_value = match.group(1)
# Find the matching closing brace by counting braces # Find the matching closing brace by counting braces
brace_count = 0 brace_count = 0
@ -98,7 +113,24 @@ class CustomProvider(LLMProvider):
try: try:
json_str = content[json_start:json_end] json_str = content[json_start:json_end]
tool_obj = json_repair.loads(json_str) tool_obj = json_repair.loads(json_str)
# Only accept if it has both name and parameters, and name is a valid tool name
# Handle calendar tool format: {"action": "...", ...}
if isinstance(tool_obj, dict) and "action" in tool_obj:
# This is a calendar tool call in JSON format
action = tool_obj.get("action")
if action and action in ["list_events", "create_event", "update_event", "delete_event", "delete_events", "check_availability"]:
# Convert to calendar tool call format
tool_calls.append(ToolCallRequest(
id=f"call_{len(tool_calls)}",
name="calendar",
arguments=tool_obj # Pass the whole object as arguments
))
# Remove the tool call from content
content = content[:json_start] + content[json_end:].strip()
start_pos = json_start # Stay at same position since we removed text
continue
# Handle standard format: {"name": "...", "parameters": {...}}
# Note: This list should match tools registered in AgentLoop._register_default_tools() # Note: This list should match tools registered in AgentLoop._register_default_tools()
valid_tools = [ valid_tools = [
# File tools # File tools

View File

@ -46,6 +46,7 @@ dependencies = [
"google-api-python-client>=2.0.0", "google-api-python-client>=2.0.0",
"google-auth-httplib2>=0.2.0", "google-auth-httplib2>=0.2.0",
"google-auth-oauthlib>=1.0.0", "google-auth-oauthlib>=1.0.0",
"pytz>=2024.1",
] ]
[project.optional-dependencies] [project.optional-dependencies]