Zeetay
style: replace box diagram with a list, normalize unicode to ASCII, trim comments
98ee05e
Raw
History Blame Contribute Delete
3.11 kB
"""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,
}