#!/usr/bin/env python3
"""
Content Repurposing Agent — runnable demo (Agent Blueprint from AgentKits)

This runs a REAL agent loop: it sends the kit's actual system prompt and a
realistic sample input to the model, prints the structured decision, and then
executes any proposed actions against MOCK tools (labelled [MOCK]).

The model/reasoning is real. The tools are stubs that return fake data and do
NOT touch any real system. Wiring the mock tools to your own integrations
(CRM, database, GitHub, etc.) is the final implementation step — see README.md.

Works with Anthropic OR OpenAI — it auto-detects whichever API key is set.

© 2026 AgentKits · www.agent-kits.com · Licensed CC BY 4.0 (attribution required)
Original blueprint: https://agent-kits.com/kit/content-repurposer

Setup (pick one):
    pip install anthropic   &&  export ANTHROPIC_API_KEY=sk-ant-...
    pip install openai      &&  export OPENAI_API_KEY=sk-...
Then:
    python run.py
"""
import os, json, sys

ANTHROPIC_MODEL = "claude-sonnet-4-6"
OPENAI_MODEL = "gpt-4o"

SYSTEM_PROMPT = """You are a Content Repurposing Agent for a marketing team. You adapt ONE source piece into requested formats (e.g. LinkedIn post, email, X thread, summary) while staying faithful to the source and on brand. You are judged on useful, on-voice repurposing and on never fabricating a fact, stat, quote, or claim.

== CORE PRINCIPLES ==
1. Faithful to the source. Every factual statement, number, and quote in your output must come from the source. Repurposing changes the format and framing, not the facts.
2. No invented credibility. Do not add statistics, study citations, customer quotes, or strong claims that aren't in the source. If the user wants a new claim, flag that it must be provided/verified — don't manufacture it.
3. On brand, not over-claimed. Match the requested voice and format, but never inflate ("good" doesn't become "the best ever") or overstate results beyond what the source supports.

== HARD RULES (NON-NEGOTIABLE) ==
- NO FABRICATION: Never invent stats, percentages, quotes, study references, or claims. Keep numbers exactly as written in the source. If something isn't in the source, it doesn't go in the output.
- ATTRIBUTE CORRECTLY: Quotes must be attributed to whoever actually said them in the source; don't reassign or invent speakers.
- NO PLAGIARISM: Transform the user's own source into new formats. Don't copy external/third-party text as if it were original.
- FLAG UNVERIFIED/SENSITIVE: Mark any claim that should be verified, any regulated/sensitive claim (health, financial, legal), and anything needing human review before publishing.
- PRESERVE MEANING: Don't distort the source's point to make a punchier post.

== METHOD ==
- Read the source; extract the key points, real stats, and real quotes. For each requested format, adapt structure/length/voice while carrying only sourced facts. Flag claims to verify.

== OUTPUT FORMAT (return ONE JSON object) ==
{
  "source_summary": "<faithful 1-2 sentence gist>",
  "outputs": [ { "format": "<linkedin|email|thread|summary|...>", "content": "<repurposed copy>", "facts_used": ["<sourced facts/stats reflected>"] } ],
  "preserved_stats": ["<numbers carried exactly from source>"],
  "quotes": [ { "quote": "<from source>", "attributed_to": "<as in source>" } ],
  "flags": ["<claims to verify / sensitive claims / needs review>"],
  "note": "Repurposes the provided source only — no facts, stats, or quotes were invented."
}
Never add a stat, quote, or claim not in the source. Flag anything the user must verify.
"""

SAMPLE_INPUT = """Source: a blog post announcing a feature that 'cut onboarding time from 5 days to 2 days' for early customers.
"""

# ---- MOCK tools (stubs — replace with real integrations to deploy) ----
def get_source(args=None):
    print(f"  [MOCK] get_source(" + str(args) + ")")
    return {"status": "mock", "tool": "get_source"}

def extract_key_points(args=None):
    print(f"  [MOCK] extract_key_points(" + str(args) + ")")
    return {"status": "mock", "tool": "extract_key_points"}

def adapt_format(args=None):
    print(f"  [MOCK] adapt_format(" + str(args) + ")")
    return {"status": "mock", "tool": "adapt_format"}

def preserve_facts_check(args=None):
    print(f"  [MOCK] preserve_facts_check(" + str(args) + ")")
    return {"status": "mock", "tool": "preserve_facts_check"}

def brand_voice(args=None):
    print(f"  [MOCK] brand_voice(" + str(args) + ")")
    return {"status": "mock", "tool": "brand_voice"}

def attribution_check(args=None):
    print(f"  [MOCK] attribution_check(" + str(args) + ")")
    return {"status": "mock", "tool": "attribution_check"}

def flag_claims(args=None):
    print(f"  [MOCK] flag_claims(" + str(args) + ")")
    return {"status": "mock", "tool": "flag_claims"}

def summarize(args=None):
    print(f"  [MOCK] summarize(" + str(args) + ")")
    return {"status": "mock", "tool": "summarize"}

TOOLS = {
    "get_source": get_source,
    "extract_key_points": extract_key_points,
    "adapt_format": adapt_format,
    "preserve_facts_check": preserve_facts_check,
    "brand_voice": brand_voice,
    "attribution_check": attribution_check,
    "flag_claims": flag_claims,
    "summarize": summarize,
}


def call_model(system, user):
    """Dispatch to whichever provider's key is configured."""
    if os.environ.get("ANTHROPIC_API_KEY"):
        try:
            from anthropic import Anthropic
        except ImportError:
            sys.exit("Run: pip install anthropic")
        msg = Anthropic().messages.create(
            model=ANTHROPIC_MODEL,
            max_tokens=1600,
            system=system,
            messages=[{"role": "user", "content": user}],
        )
        return "".join(b.text for b in msg.content if getattr(b, "type", "") == "text")
    if os.environ.get("OPENAI_API_KEY"):
        try:
            from openai import OpenAI
        except ImportError:
            sys.exit("Run: pip install openai")
        resp = OpenAI().chat.completions.create(
            model=OPENAI_MODEL,
            max_tokens=1600,
            messages=[
                {"role": "system", "content": system},
                {"role": "user", "content": user},
            ],
        )
        return resp.choices[0].message.content
    sys.exit("Set ANTHROPIC_API_KEY or OPENAI_API_KEY first.")


def extract_json(text):
    a, b = text.find("{"), text.rfind("}")
    if a == -1 or b == -1:
        return None
    try:
        return json.loads(text[a : b + 1])
    except json.JSONDecodeError:
        return None


def main():
    print("=" * 70)
    print("INPUT:\n" + SAMPLE_INPUT)
    print("=" * 70)

    text = call_model(SYSTEM_PROMPT, SAMPLE_INPUT)
    print("AGENT DECISION:\n" + text)
    print("=" * 70)

    data = extract_json(text)
    if not data:
        print("(No JSON object parsed — the model returned prose.)")
        return

    actions = data.get("actions") or []
    if actions:
        print("EXECUTING PROPOSED ACTIONS (mock):")
        for a in actions:
            name = a.get("tool")
            args = a.get("args", {})
            if name in TOOLS:
                TOOLS[name](args)
            else:
                print(f"  [skip] no mock tool for '{name}'")
    else:
        print("This blueprint returned a structured result (no side-effecting "
              "actions in this sample). Available mock tools: "
              + ", ".join(TOOLS.keys()))


if __name__ == "__main__":
    main()
