This repo compares four ways to run the same task.
The task stays fixed. The orchestration changes.
workflowruns a fixed graph.workflow_with_fetchruns the same graph with a hardcoded fetch step.singlegives one agent only fetch and search tools.multisplits the work between a supervisor and specialists.
The code answers two questions about a piece of content:
- Is the writing manipulative?
- Are the claims false or misleading?
src/contours.py: shared analysis logicsrc/workflow_graph.py: fixed graphsrc/workflow_with_fetch.py: fixed graph with URL fetchsrc/single_agent.py: one raw agent over low-level toolssrc/multi_agent.py: supervisor + specialistsstreamlit_app.py: UIeval/: regression and contrastive evals
uv sync
cp .env.example .envAdd GEMINI_API_KEY to .env.
The app and CLI stop at startup if the key is missing.
Optional keys:
TAVILY_API_KEYLANGFUSE_PUBLIC_KEYLANGFUSE_SECRET_KEYLANGFUSE_HOSTorLANGFUSE_BASE_URL
Without Tavily, the retrieval path falls back to a mock. Without Langfuse, the runs still work but you get no traces.
uv run streamlit run streamlit_app.pyThe UI shows one shared manipulation panel and one result row per architecture.
eval/dataset.jsonl: clean text exampleseval/hard_dataset.jsonl: URL, YouTube, and noisy inputseval/euvsdisinfo_cases.jsonl: real EUvsDisinfo cases
uv run python eval/run_eval.py
uv run python eval/run_contrastive.py
uv run python eval/debuggability.pyrun_eval.pycompares accuracy and cost.run_contrastive.pyshows where the plain workflow fails.debuggability.pymeasures variance, handoffs, and span depth.
RUNBOOK.md: step-by-step demo flowdocs/architectures.md: diagramsARD.md: problem, data, eval, architecture