"""Content Variant Generator Tool Generates multiple variations of marketing content for A/B testing. Supports testing different hooks, tones, lengths, and psychological angles. """ from typing import Optional from pydantic import Field from config import TEMPERATURE_HIGHLY_CREATIVE from systemprompts import CONTENTVARIANT_PROMPT from tools.models import ToolModelCategory from tools.shared.base_models import ToolRequest from tools.simple.base import SimpleTool class ContentVariantRequest(ToolRequest): """Request model for Content Variant Generator""" content: str = Field( ..., description="Base content or topic to create variations from. Can be a draft post, subject line, or content concept.", ) variation_count: int = Field( default=10, ge=5, le=25, description="Number of variations to generate (5-25). Default is 10.", ) variation_types: Optional[list[str]] = Field( default=None, description="Types of variations to explore: 'hook', 'tone', 'length', 'structure', 'cta', 'angle'. Leave empty for mixed approach.", ) platform: Optional[str] = Field( default=None, description="Target platform for character limits and formatting: 'twitter', 'bluesky', 'linkedin', 'instagram', 'facebook', 'email_subject', 'blog'", ) constraints: Optional[str] = Field( default=None, description="Additional constraints: character limits, style requirements, brand voice guidelines, prohibited words/phrases", ) testing_angles: Optional[list[str]] = Field( default=None, description="Specific psychological angles to test: 'curiosity', 'contrarian', 'knowledge_gap', 'urgency', 'insider', 'problem_solution', 'social_proof', 'transformation'", ) class ContentVariantTool(SimpleTool): """Generate multiple content variations for A/B testing""" def get_name(self) -> str: return "contentvariant" def get_description(self) -> str: return ( "Generate 5-25 variations of marketing content for A/B testing. " "Tests different hooks, tones, lengths, and psychological angles. " "Ideal for subject lines, social posts, email copy, and ads. " "Each variation includes testing rationale and predicted audience response." ) def get_system_prompt(self) -> str: return CONTENTVARIANT_PROMPT def get_default_temperature(self) -> float: return TEMPERATURE_HIGHLY_CREATIVE def get_model_category(self) -> ToolModelCategory: return ToolModelCategory.FAST_RESPONSE def get_request_model(self): return ContentVariantRequest def get_tool_fields(self) -> dict: """ Tool-specific field definitions for ContentVariant. Note: This method isn't used since we override get_input_schema(), but it's required by the SimpleTool abstract base class. """ return { "content": { "type": "string", "description": "Base content or topic to create variations from", } } async def prepare_prompt(self, request: ContentVariantRequest) -> str: """Prepare the content variant prompt""" prompt_parts = [f"Generate {request.variation_count} variations of this content:"] prompt_parts.append(f"\n**Base Content:**\n{request.content}") if request.platform: prompt_parts.append(f"\n**Target Platform:** {request.platform}") if request.variation_types: prompt_parts.append(f"\n**Variation Types:** {', '.join(request.variation_types)}") if request.testing_angles: prompt_parts.append(f"\n**Testing Angles:** {', '.join(request.testing_angles)}") if request.constraints: prompt_parts.append(f"\n**Constraints:** {request.constraints}") prompt_parts.append( "\nGenerate variations with clear labels, character counts (if platform specified), " "testing angles, and predicted audience responses." ) # Use SimpleTool's chat-style prompt preparation request.prompt = "\n".join(prompt_parts) return self.prepare_chat_style_prompt(request) def get_input_schema(self) -> dict: """Return the JSON schema for this tool's input""" return { "type": "object", "properties": { "content": { "type": "string", "description": "Base content or topic to create variations from", }, "variation_count": { "type": "integer", "description": "Number of variations to generate (5-25, default 10)", "minimum": 5, "maximum": 25, "default": 10, }, "variation_types": { "type": "array", "items": {"type": "string"}, "description": "Types: 'hook', 'tone', 'length', 'structure', 'cta', 'angle'", }, "platform": { "type": "string", "description": "Platform: 'twitter', 'bluesky', 'linkedin', 'instagram', 'facebook', 'email_subject', 'blog'", }, "constraints": { "type": "string", "description": "Character limits, style requirements, brand guidelines", }, "testing_angles": { "type": "array", "items": {"type": "string"}, "description": "Angles: 'curiosity', 'contrarian', 'knowledge_gap', 'urgency', 'insider', 'problem_solution', 'social_proof', 'transformation'", }, "files": { "type": "array", "items": {"type": "string"}, "description": "Optional brand guidelines or style reference files", }, "images": { "type": "array", "items": {"type": "string"}, "description": "Optional visual assets for context", }, "continuation_id": { "type": "string", "description": "Thread ID to continue previous conversation", }, "model": { "type": "string", "description": "AI model to use (leave empty for default fast model)", }, "temperature": { "type": "number", "description": "Creativity level 0.0-1.0 (default 0.8 for high variation)", "minimum": 0.0, "maximum": 1.0, }, "thinking_mode": { "type": "string", "description": "Thinking depth: minimal, low, medium, high, max", "enum": ["minimal", "low", "medium", "high", "max"], }, "use_websearch": { "type": "boolean", "description": "Enable web search for current platform best practices", "default": False, }, }, "required": ["content"], }