""" Trillium notes executor for searching and creating notes via ETAPI. This module provides integration with Trillium notes through the ETAPI HTTP API. """ import os import aiohttp from typing import Dict TRILLIUM_URL = os.getenv("TRILLIUM_URL", "http://localhost:8080") TRILLIUM_TOKEN = os.getenv("TRILLIUM_ETAPI_TOKEN", "") async def search_notes(args: Dict) -> Dict: """Search Trillium notes via ETAPI. Args: args: Dictionary containing: - query (str): Search query - limit (int, optional): Maximum notes to return (default: 5, max: 20) Returns: dict: Search results containing: - notes (list): List of notes with noteId, title, content, type - count (int): Number of notes returned OR - error (str): Error message if search failed """ query = args.get("query") limit = args.get("limit", 5) # Validation if not query: return {"error": "No query provided"} if not TRILLIUM_TOKEN: return {"error": "TRILLIUM_ETAPI_TOKEN not configured in environment"} # Cap limit limit = min(max(limit, 1), 20) try: async with aiohttp.ClientSession() as session: async with session.get( f"{TRILLIUM_URL}/etapi/search-notes", params={"search": query, "limit": limit}, headers={"Authorization": TRILLIUM_TOKEN} ) as resp: if resp.status == 200: data = await resp.json() return { "notes": data, "count": len(data) } elif resp.status == 401: return {"error": "Authentication failed. Check TRILLIUM_ETAPI_TOKEN"} else: error_text = await resp.text() return {"error": f"HTTP {resp.status}: {error_text}"} except aiohttp.ClientConnectorError: return {"error": f"Cannot connect to Trillium at {TRILLIUM_URL}"} except Exception as e: return {"error": f"Search failed: {str(e)}"} async def create_note(args: Dict) -> Dict: """Create a note in Trillium via ETAPI. Args: args: Dictionary containing: - title (str): Note title - content (str): Note content in markdown or HTML - parent_note_id (str, optional): Parent note ID to nest under Returns: dict: Creation result containing: - noteId (str): ID of created note - title (str): Title of created note - success (bool): True if created successfully OR - error (str): Error message if creation failed """ title = args.get("title") content = args.get("content") parent_note_id = args.get("parent_note_id") # Validation if not title: return {"error": "No title provided"} if not content: return {"error": "No content provided"} if not TRILLIUM_TOKEN: return {"error": "TRILLIUM_ETAPI_TOKEN not configured in environment"} # Prepare payload payload = { "title": title, "content": content, "type": "text", "mime": "text/html" } if parent_note_id: payload["parentNoteId"] = parent_note_id try: async with aiohttp.ClientSession() as session: async with session.post( f"{TRILLIUM_URL}/etapi/create-note", json=payload, headers={"Authorization": TRILLIUM_TOKEN} ) as resp: if resp.status in [200, 201]: data = await resp.json() return { "noteId": data.get("noteId"), "title": title, "success": True } elif resp.status == 401: return {"error": "Authentication failed. Check TRILLIUM_ETAPI_TOKEN"} else: error_text = await resp.text() return {"error": f"HTTP {resp.status}: {error_text}"} except aiohttp.ClientConnectorError: return {"error": f"Cannot connect to Trillium at {TRILLIUM_URL}"} except Exception as e: return {"error": f"Note creation failed: {str(e)}"}