Spaces:
Sleeping
Sleeping
| """The main agent loop: retrieve -> generate -> evaluate -> store -> feedback. | |
| Synchronous and dependency-injected so the API, CLI, and tests share one path. | |
| """ | |
| from typing import Any, Optional | |
| from agent import prompts, tools | |
| from agent.memory import Memory | |
| from db.store import Store | |
| # The three variants the agent always produces, in order. | |
| VARIANT_TYPES = ("headline", "body", "cta") | |
| class Agent: | |
| def __init__( | |
| self, | |
| store: Optional[Store] = None, | |
| memory: Optional[Memory] = None, | |
| temperature: float = 0.7, | |
| ): | |
| self.store = store or Store() | |
| self.memory = memory or Memory() | |
| self.temperature = temperature | |
| def generate_variants(self, brief: dict[str, Any], few_shot_block: str, prompt_version: str) -> dict[str, str]: | |
| """Call the LLM once and parse out the three ad-copy variants.""" | |
| prompt = prompts.render_generation_prompt(brief, few_shot_block, prompt_version) | |
| raw = tools.chat(prompt, temperature=self.temperature) | |
| parsed = tools.extract_json(raw) | |
| return { | |
| "headline": str(parsed.get("headline", "")).strip(), | |
| "body": str(parsed.get("body", "")).strip(), | |
| "cta": str(parsed.get("cta", "")).strip(), | |
| } | |
| def run(self, brief: dict[str, Any]) -> dict[str, Any]: | |
| """Execute the full loop for one brand brief and return outputs + scores.""" | |
| # imported here to avoid an import cycle (core <-> evals/feedback) | |
| from evals.judge import judge_output | |
| from feedback.loop import run_feedback | |
| prompt_version = prompts.ACTIVE_PROMPT_VERSION | |
| retrieved = self.memory.retrieve(brief, k=3) | |
| few_shot_block = prompts.build_few_shot_block(retrieved) | |
| variants = self.generate_variants(brief, few_shot_block, prompt_version) | |
| # judge each variant and persist the run | |
| run_id = self.store.create_run(brief, prompt_version) | |
| scored_outputs: list[dict[str, Any]] = [] | |
| for variant_type in VARIANT_TYPES: | |
| content = variants[variant_type] | |
| scores = judge_output(brief, variant_type, content) | |
| self.store.add_output(run_id, variant_type, content, scores, prompt_version) | |
| scored_outputs.append( | |
| { | |
| "variant_type": variant_type, | |
| "content": content, | |
| "scores": scores, | |
| } | |
| ) | |
| # promote winners to golden + memory, flag the weak ones | |
| feedback_summary = run_feedback( | |
| store=self.store, | |
| memory=self.memory, | |
| brief=brief, | |
| run_id=run_id, | |
| scored_outputs=scored_outputs, | |
| prompt_version=prompt_version, | |
| ) | |
| return { | |
| "run_id": run_id, | |
| "brief": brief, | |
| "prompt_version": prompt_version, | |
| "retrieved_examples": len(retrieved), | |
| "retrieved_count": len(retrieved), # what the frontend reads | |
| "outputs": scored_outputs, | |
| "feedback": feedback_summary, | |
| } | |