"""Copywriter agent: generates product descriptions and social captions.""" from jinja2 import Template from agents.llm import LLMClient from agents.models import AgentTrace, CatalogerOutput, CopywriterOutput SYSTEM_PROMPT = ( "You are a warm, authentic copywriter for handmade crafts. You write " "product descriptions and social media captions that feel personal and " "artisan -- never corporate or salesy.\n\n" "Your tone: warm, genuine, storytelling, inviting. Write as if a real " "craftsperson is sharing their work.\n\n" "Always respond with valid JSON." ) USER_TEMPLATE = Template( "Write marketing copy for this {{ craft_type }} item:\n\n" "Category: {{ catalog.category }} / {{ catalog.sub_category }}\n" "Materials: {{ catalog.materials | join(', ') }}\n" "Colors: {{ catalog.colors | join(', ') }}\n" "Size: {{ catalog.estimated_size }}\n" "Complexity: {{ catalog.complexity }}\n" "{% if user_notes %}Creator's notes: {{ user_notes }}{% endif %}\n\n" "Provide:\n" "1. A catchy product title (under 60 characters)\n" "2. A short description (1-2 sentences)\n" "3. A longer description (1 paragraph, warm and personal)\n" "4. Exactly 3 Instagram caption variations (each under 200 characters, " "include relevant hashtags)" ) async def run( llm: LLMClient, craft_type: str, catalog: CatalogerOutput, user_notes: str | None = None, ) -> tuple[CopywriterOutput, AgentTrace]: prompt = USER_TEMPLATE.render( craft_type=craft_type, catalog=catalog, user_notes=user_notes, ) result, duration_ms = await llm.agenerate( system=SYSTEM_PROMPT, prompt=prompt, output_schema=CopywriterOutput, max_tokens=1024, ) trace = AgentTrace( agent_name="copywriter", input_text=prompt, output_data=result.model_dump(), duration_ms=duration_ms, model_id=llm.model_id, ) return result, trace