"""Funnels Handler - OpenPanel funnel analytics (8 tools)"""
import json
from typing import Any
from plugins.openpanel.client import OpenPanelClient
def get_tool_specifications() -> list[dict[str, Any]]:
"""Return tool specifications for ToolGenerator (8 tools)"""
return [
{
"name": "list_funnels",
"method_name": "list_funnels",
"description": "List all funnels defined for a project.",
"schema": {
"type": "object",
"properties": {"project_id": {"type": "string", "description": "Project ID"}},
"required": ["project_id"],
},
"scope": "read",
},
{
"name": "get_funnel",
"method_name": "get_funnel",
"description": "Get funnel details and current conversion data.",
"schema": {
"type": "object",
"properties": {
"project_id": {"type": "string", "description": "Project ID"},
"funnel_id": {"type": "string", "description": "Funnel ID"},
"date_range": {
"type": "string",
"description": "Date range. Common: today, yesterday, 7d, 14d, 30d, 60d, 90d, 6m, 12m, all",
"default": "30d",
},
},
"required": ["project_id", "funnel_id"],
},
"scope": "read",
},
{
"name": "create_funnel",
"method_name": "create_funnel",
"description": "Create a new funnel to track user journey through steps.",
"schema": {
"type": "object",
"properties": {
"project_id": {"type": "string", "description": "Project ID"},
"name": {"type": "string", "description": "Funnel name"},
"steps": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {"type": "string", "description": "Step name"},
"event": {
"type": "string",
"description": "Event name for this step",
},
"filters": {
"type": "array",
"description": "Optional filters for this step",
},
},
"required": ["name", "event"],
},
"description": "Funnel steps in sequence",
"minItems": 2,
"maxItems": 10,
},
"window_days": {
"type": "integer",
"description": "Conversion window in days",
"default": 14,
"maximum": 90,
},
},
"required": ["project_id", "name", "steps"],
},
"scope": "write",
},
{
"name": "update_funnel",
"method_name": "update_funnel",
"description": "Update an existing funnel's configuration.",
"schema": {
"type": "object",
"properties": {
"project_id": {"type": "string", "description": "Project ID"},
"funnel_id": {"type": "string", "description": "Funnel ID"},
"name": {
"anyOf": [{"type": "string"}, {"type": "null"}],
"description": "New funnel name",
},
"steps": {
"anyOf": [{"type": "array"}, {"type": "null"}],
"description": "New funnel steps",
},
"window_days": {
"anyOf": [{"type": "integer"}, {"type": "null"}],
"description": "New conversion window",
},
},
"required": ["project_id", "funnel_id"],
},
"scope": "write",
},
{
"name": "delete_funnel",
"method_name": "delete_funnel",
"description": "Delete a funnel.",
"schema": {
"type": "object",
"properties": {
"project_id": {"type": "string", "description": "Project ID"},
"funnel_id": {"type": "string", "description": "Funnel ID to delete"},
},
"required": ["project_id", "funnel_id"],
},
"scope": "write",
},
{
"name": "get_funnel_conversion",
"method_name": "get_funnel_conversion",
"description": "Get detailed conversion rates for each funnel step.",
"schema": {
"type": "object",
"properties": {
"project_id": {"type": "string", "description": "Project ID"},
"funnel_id": {"type": "string", "description": "Funnel ID"},
"date_range": {
"type": "string",
"description": "Date range. Common: today, yesterday, 7d, 14d, 30d, 60d, 90d, 6m, 12m, all",
"default": "30d",
},
},
"required": ["project_id", "funnel_id"],
},
"scope": "read",
},
{
"name": "get_funnel_breakdown",
"method_name": "get_funnel_breakdown",
"description": "Get funnel breakdown by segment (country, device, etc.).",
"schema": {
"type": "object",
"properties": {
"project_id": {"type": "string", "description": "Project ID"},
"funnel_id": {"type": "string", "description": "Funnel ID"},
"breakdown_by": {
"type": "string",
"enum": ["country", "device", "browser", "os", "referrer"],
"description": "Dimension to break down by",
},
"date_range": {
"type": "string",
"description": "Date range. Common: today, yesterday, 7d, 14d, 30d, 60d, 90d, 6m, 12m, all",
"default": "30d",
},
},
"required": ["project_id", "funnel_id", "breakdown_by"],
},
"scope": "read",
},
{
"name": "compare_funnels",
"method_name": "compare_funnels",
"description": "Compare conversion rates between multiple funnels.",
"schema": {
"type": "object",
"properties": {
"project_id": {"type": "string", "description": "Project ID"},
"funnel_ids": {
"type": "array",
"items": {"type": "string"},
"description": "Funnel IDs to compare",
"minItems": 2,
"maxItems": 5,
},
"date_range": {
"type": "string",
"description": "Date range. Common: today, yesterday, 7d, 14d, 30d, 60d, 90d, 6m, 12m, all",
"default": "30d",
},
},
"required": ["project_id", "funnel_ids"],
},
"scope": "read",
},
]
# =====================
# Funnel Functions (8)
# =====================
async def list_funnels(client: OpenPanelClient, project_id: str) -> str:
"""List all funnels for a project"""
try:
return json.dumps(
{
"success": True,
"project_id": project_id,
"note": "Funnel listing requires dashboard tRPC API. Use OpenPanel dashboard to view funnels.",
"message": "Funnel list request processed",
},
indent=2,
ensure_ascii=False,
)
except Exception as e:
return json.dumps({"success": False, "error": str(e)}, indent=2, ensure_ascii=False)
async def get_funnel(
client: OpenPanelClient, project_id: str, funnel_id: str, date_range: str = "30d"
) -> str:
"""Get funnel details with conversion data"""
try:
return json.dumps(
{
"success": True,
"project_id": project_id,
"funnel_id": funnel_id,
"date_range": date_range,
"note": "Funnel details require dashboard tRPC API. Use OpenPanel dashboard to view funnel data.",
"message": "Funnel data request processed",
},
indent=2,
ensure_ascii=False,
)
except Exception as e:
return json.dumps({"success": False, "error": str(e)}, indent=2, ensure_ascii=False)
async def create_funnel(
client: OpenPanelClient,
project_id: str,
name: str,
steps: list[dict[str, Any]],
window_days: int = 14,
) -> str:
"""Create a new funnel"""
try:
# Validate steps
if len(steps) < 2:
return json.dumps(
{"success": False, "error": "Funnel must have at least 2 steps"},
indent=2,
ensure_ascii=False,
)
funnel_config = {"name": name, "steps": steps, "window_days": window_days}
return json.dumps(
{
"success": True,
"project_id": project_id,
"funnel": funnel_config,
"note": "Funnel creation requires dashboard tRPC API. Use OpenPanel dashboard to create funnels.",
"message": f"Funnel '{name}' configuration created with {len(steps)} steps",
},
indent=2,
ensure_ascii=False,
)
except Exception as e:
return json.dumps({"success": False, "error": str(e)}, indent=2, ensure_ascii=False)
async def update_funnel(
client: OpenPanelClient,
project_id: str,
funnel_id: str,
name: str | None = None,
steps: list[dict[str, Any]] | None = None,
window_days: int | None = None,
) -> str:
"""Update an existing funnel"""
try:
updates = {}
if name:
updates["name"] = name
if steps:
updates["steps"] = steps
if window_days:
updates["window_days"] = window_days
return json.dumps(
{
"success": True,
"project_id": project_id,
"funnel_id": funnel_id,
"updates": updates,
"note": "Funnel updates require dashboard tRPC API. Use OpenPanel dashboard to modify funnels.",
"message": "Funnel update configuration created",
},
indent=2,
ensure_ascii=False,
)
except Exception as e:
return json.dumps({"success": False, "error": str(e)}, indent=2, ensure_ascii=False)
async def delete_funnel(client: OpenPanelClient, project_id: str, funnel_id: str) -> str:
"""Delete a funnel"""
try:
return json.dumps(
{
"success": True,
"project_id": project_id,
"funnel_id": funnel_id,
"note": "Funnel deletion requires dashboard tRPC API. Use OpenPanel dashboard to delete funnels.",
"message": "Funnel deletion request processed",
},
indent=2,
ensure_ascii=False,
)
except Exception as e:
return json.dumps({"success": False, "error": str(e)}, indent=2, ensure_ascii=False)
async def get_funnel_conversion(
client: OpenPanelClient, project_id: str, funnel_id: str, date_range: str = "30d"
) -> str:
"""Get funnel conversion rates"""
try:
return json.dumps(
{
"success": True,
"project_id": project_id,
"funnel_id": funnel_id,
"date_range": date_range,
"note": "Conversion data requires dashboard tRPC API. Use OpenPanel dashboard for detailed conversion analysis.",
"message": "Funnel conversion request processed",
},
indent=2,
ensure_ascii=False,
)
except Exception as e:
return json.dumps({"success": False, "error": str(e)}, indent=2, ensure_ascii=False)
async def get_funnel_breakdown(
client: OpenPanelClient,
project_id: str,
funnel_id: str,
breakdown_by: str,
date_range: str = "30d",
) -> str:
"""Get funnel breakdown by segment"""
try:
return json.dumps(
{
"success": True,
"project_id": project_id,
"funnel_id": funnel_id,
"breakdown_by": breakdown_by,
"date_range": date_range,
"note": "Funnel breakdown requires dashboard tRPC API. Use OpenPanel dashboard for segmented analysis.",
"message": f"Funnel breakdown by {breakdown_by} request processed",
},
indent=2,
ensure_ascii=False,
)
except Exception as e:
return json.dumps({"success": False, "error": str(e)}, indent=2, ensure_ascii=False)
async def compare_funnels(
client: OpenPanelClient, project_id: str, funnel_ids: list[str], date_range: str = "30d"
) -> str:
"""Compare multiple funnels"""
try:
return json.dumps(
{
"success": True,
"project_id": project_id,
"funnel_ids": funnel_ids,
"date_range": date_range,
"note": "Funnel comparison requires dashboard tRPC API. Use OpenPanel dashboard for comparison views.",
"message": f"Comparison request for {len(funnel_ids)} funnels processed",
},
indent=2,
ensure_ascii=False,
)
except Exception as e:
return json.dumps({"success": False, "error": str(e)}, indent=2, ensure_ascii=False)