Skip to content

morganwilliscloud/browns-agent

Repository files navigation

🐶 Cleveland Browns Emotional Support Agent

Demo agent for a 30-minute PyOhio talk, built with the Strands Agents SDK. Each stage adds one building block. The agent is unshakably optimistic — it genuinely believes this is the Browns' year, every single year.

Setup

python3 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
aws configure   # needs Bedrock model access (Claude Sonnet)

# One-time, for the guardrail stage (and the frontend/full agent, optionally):
python setup_guardrail.py
export BROWNS_GUARDRAIL_ID=<printed id>

# One-time, for the persistent memory stage:
python setup_memory.py
export BROWNS_MEMORY_ID=<printed id>

Stages

# File Concept The moment
1 01_minimal_agent.py Agent in a few lines Interactive chat, pure belief, no tools
2 02_agent_loop_trace.py The agent loop Watch model → tool → model in agent.messages
3 03_tools.py Tools (@tool) Real nflverse stats: 5-12 spun as "underestimated"
4 04_hooks_and_interrupts.py State + hooks + interrupts DEFCON DAWG POUND → "Authorize Emergency Bar Protocol?"
5 05_guardrails.py Bedrock Guardrails Sadness passes, trash talk gets BLOCKED
6 06_conversation_mgmt.py Conversation management A season of suffering, summarized
7 07_persistent_memory.py AgentCore Memory Quit, restart — it still remembers your hot takes
full_agent.py Everything composed Interactive terminal REPL

Run any stage: python 04_hooks_and_interrupts.py

Frontend

export BROWNS_GUARDRAIL_ID=<id>   # optional — enables the guardrail in the UI
streamlit run frontend/app.py

Browns-themed chat with a live pain gauge (sidebar, with sparkline). When pain peaks past the threshold, the frontend auto-authorizes the Emergency Bar Location Protocol: a banner and map drop into the chat with the nearest Browns Backers bar pinned, the gauge holds at the peak ("💀 DEFCON DAWG POUND") for the crisis turn, then vitals stabilize. Casual "where should I watch the game" requests get a quiet approval — no sirens.

Architecture

  • Model knowledge handles Browns history, trivia, and coping — no tool needed. (It also gets today's date and the NFL season convention injected into the system prompt, so "last season" resolves correctly.)
  • Tools return plain data; the personality lives in the system prompt. Real stats via nflverse (nflreadpy — games/plays back to 1999, players, draft; free, no key, cached locally so it works offline), NWS weather (real API, no key), bar lookup (fictional bars), and pain reporting.
  • The model decides the pain delta each turn via update_pain_index — it understands context better than keyword matching. The tool stores it in agent state (shared with hooks, costs zero context tokens).
  • The hook (hooks/pain_monitor_hook.py) shows both hook superpowers in ~30 lines:
    • AfterToolCallEvent — when pain crosses the threshold, append an emergency directive to the pain tool's result (the model sees it and calls the bar tool); once the bar is delivered, reset the pain index — the intervention works.
    • BeforeToolCallEvent — every bar dispatch pauses the loop with an interrupt for human sign-off. Terminal demos ask y/N; the frontend auto-authorizes.
  • The guardrail (browns-loyalty-guardrail, STANDARD tier) blocks insults aimed at the Browns while letting fan grief through. The blocked-input message does the comedy: "This is a SAFE SPACE for BELIEVERS."
  • Memory (stage 7) uses AgentCore Memory via a Strands session manager — session summaries, fan preferences, and facts persist across restarts (three long-term strategies configured in setup_memory.py).

Flow: Model reports → Tool stores → Hook escalates → Model reacts → Hook interrupts → Human decides

Demo pacing notes

  • Pain climbs over a few turns: calm questions score ~0, bad news +1/+2, real trauma (The Drive / The Fumble / Red Right 88) or despair +3 to +5. Two heavy turns reliably cross the threshold. Tune PAIN_THRESHOLD in hooks/pain_monitor_hook.py if needed.
  • Stats are real (nflverse) and cached locally after first load — run each stage once before the talk so the parquet cache is warm and offline-safe. The weather tool hits the live NWS API (which throws the occasional 500 — rehearse it). Bars are intentionally fictional.
  • Guardrail note: the topic definition needs the explicit "sadness is NOT this topic" carve-out and the STANDARD tier, or it blocks sad-but-loyal fans too.

Powered by Strands Agents SDK | Go Dawgs 🐶

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages