# Lilith Agent — Architecture Three views: **system** (entry → graph → outputs), **ReAct graph** (state machine), **tool belt** (tool taxonomy + dependencies). ## System overview ```mermaid flowchart TB subgraph Entry["Entry points"] TUI["tui.py
(lilith CLI)"] CLI["scripts/dev_run_gaia.py
(batch runner)"] APP["app.py
(Gradio · HF Space)"] end subgraph Config["Config & models"] CFG["config.py
Config.from_env()"] MDL["models.py
cheap / strong / extra_strong
+ NoThink / Retry wrappers"] ENV[".env
API keys · provider+model · caveman"] ENV --> CFG --> MDL end subgraph Core["ReAct core"] BUILD["app.py :: build_react_agent(cfg)"] GRAPH["LangGraph
StateGraph(AgentState)"] RUN["runner.py
run_agent_on_questions()"] BUILD --> GRAPH RUN --> GRAPH end subgraph Data["GAIA data sources"] DS["gaia_dataset.py
GaiaDatasetClient
(HF dataset)"] SCORE["ScoringApiClient
(agents-course-unit4-
scoring.hf.space)"] end subgraph Obs["Observability"] LOG[".lilith/session-*.log"] TRACE[".lilith/session-*.jsonl
JsonlTraceCallback"] ARIZE["Arize AX
(optional)"] LS["LangSmith
(optional)"] end TUI --> BUILD TUI --> Obs CLI --> BUILD CLI --> RUN CLI --> DS APP --> BUILD APP --> RUN APP --> SCORE MDL --> BUILD GRAPH --> Obs CKPT[".checkpoints/.json"] RUN --> CKPT ``` ## ReAct graph (state machine) ```mermaid stateDiagram-v2 [*] --> model model --> tools: AIMessage has tool_calls
AND iterations < limit
AND calls < BUDGET_HARD_CAP (25) model --> fail_safe: iterations ≥ recursion_limit − 2
OR calls ≥ BUDGET_HARD_CAP model --> [*]: no tool_calls (final answer) tools --> model: results appended as ToolMessages fail_safe --> [*]: emergency summary note right of model compact old ToolMessages (keep last 4 verbatim, truncate older to 300 chars) inject BUDGET WARNING at 15 calls apply caveman prompt wrapper end note note left of tools per-call guards: 1. exact (name,args) dedup 2. semantic dedup (Jaccard ≥ 0.5) for tavily 3. per-tool error cooldown (3 fails → freeze) end note ``` ## Tool belt ```mermaid flowchart LR subgraph Web["Web & search"] WS["web_search
(DDG → Tavily fallback)"] FU["fetch_url
(trafilatura)"] end subgraph Code["Code & files"] RP["run_python
(sandboxed subprocess)"] RF["read_file"] LS_T["ls · grep · glob_files · write_file"] end subgraph Media["Media"] AUD["transcribe_audio
(faster-whisper)"] PDF["inspect_pdf"] VIS["inspect_visual_content
(Gemini → FAL → cross-provider)"] YT_T["youtube_transcript"] YT_F["youtube_frame_at
(ffmpeg)"] end subgraph Academic["Academic"] AX["arxiv_search"] CR["crossref_search"] CJ["count_journal_articles"] FE["filter_entities"] end subgraph Plan["Planning"] WT["write_todos"] MD["mark_todo_done"] end REG["tools/__init__.py
build_tools(cfg)"] REG --> Web REG --> Code REG --> Media REG --> Academic REG --> Plan VIS -. fallback chain .-> VIS YT_F --> VIS CR --> FE ``` ## Key sources | Concern | File | |---|---| | ReAct graph + routing + dedup | [src/lilith_agent/app.py](src/lilith_agent/app.py) | | Batch runner + checkpoints | [src/lilith_agent/runner.py](src/lilith_agent/runner.py) | | Config loader | [src/lilith_agent/config.py](src/lilith_agent/config.py) | | Model provider factory | [src/lilith_agent/models.py](src/lilith_agent/models.py) | | Tool registry | [src/lilith_agent/tools/__init__.py](src/lilith_agent/tools/__init__.py) | | Logging + Arize + JSONL trace | [src/lilith_agent/observability.py](src/lilith_agent/observability.py) | | HF dataset client | [src/lilith_agent/gaia_dataset.py](src/lilith_agent/gaia_dataset.py) | | Gradio Space entry | [app.py](app.py) | | Interactive TUI | [src/lilith_agent/tui.py](src/lilith_agent/tui.py) | | GAIA batch CLI | [scripts/dev_run_gaia.py](scripts/dev_run_gaia.py) |