# AGENTS.md This file provides guidance to agents when working with code in this repository. ## Project EcoAgent v2 — A Gradio Blocks web app for eco lifestyle advice, powered by **IBM Granite** (`ibm/granite-4-h-small`) via the `ibm-watsonx-ai` SDK. India-focused with 4 tabs: Chat, Dashboard, Recycling Guide, Household Profile. **Classification:** Agentic AI Application with Prompt Engineering **IBM Orchestrate REST API is NOT used** — direct SDK calls to watsonx.ai only. ## Stack - **Runtime:** Python 3.14 via `uv` (venv at `.venv/`) - **Package manager:** `uv` — always use `uv pip install` / `uv run python`, NOT bare `pip` or `python` - **UI Framework:** Gradio 6.20 (ultra-light eco green theme) - **AI Model:** IBM Granite 4 H Small (`ibm/granite-4-h-small`) via watsonx.ai eu-de - **SDK:** `ibm-watsonx-ai` >= 1.1.15 (APIClient + ModelInference pattern) - **Agent Tools:** 5 tools (Impact Calculator, Recycling Guide, Web Search, Scheme Checker, Household Profiler) - **System Python is 3.11 (Miniconda)** — unrelated to this project's venv - **Target deploy:** Hugging Face Spaces (Gradio SDK) ## Key Commands ```bash uv pip install -r requirements.txt # install deps uv run python app.py # run locally → http://localhost:7860 ``` ## Critical Gotchas - **`.env` is gitignored** — cannot be written by file tools. Use `Set-Content` PowerShell command instead. - **`WATSONX_PROJECT_ID` is mandatory** — the SDK raises an error without it. Get it from: `https://eu-de.dataplatform.cloud.ibm.com` → project → Manage → General → Project ID. - **Region is eu-de (Frankfurt)** — `WATSONX_URL=https://eu-de.ml.cloud.ibm.com`. Do not use `us-south`. - **Model lazy-init** — `_get_model()` in `watsonx_client.py` initialises `ModelInference` on the first call, not at import. Import-time errors = missing env vars. First-call errors = bad project ID or model access. - **`load_dotenv(".env")` explicit path** — both `app.py` and `watsonx_client.py` call this. The default `load_dotenv()` looks for `.env` by name; the explicit path ensures it works regardless of CWD. - **Chat history format (Gradio 6.x)** — History uses structured content blocks: `{"role": "user", "content": [{"type": "text", "text": "..."}]}`. The `chat_submit()` function extracts text for the API call and returns structured blocks for display. - **`dashboard_html` is defined inside the Tab 2 block** — it's referenced by `save_profile()` in Tab 4. Both must be inside the same `gr.Blocks` context. - **Theme/CSS in Gradio 6.x** — `theme` and `css` parameters go in `demo.launch()`, NOT in `gr.Blocks()` constructor. - **SSL_CERT_FILE** — The app auto-detects and sets the correct certifi path on startup. - **Agent Mode** — When enabled, uses agentic loop with tool calls. Max 5 iterations to prevent infinite loops. - **Web Search Date Fix** — IBM Granite ignores search results and hallucinates outdated dates. Fixed by injecting `TODAY'S DATE` into the system prompt and adding `Search conducted on: ` to search results. Never rely on LLM training data for time-sensitive information. ## Architecture ``` .env └─ WATSONX_API_KEY, WATSONX_PROJECT_ID, WATSONX_URL │ ▼ watsonx_client.py ├─ AGENT_INSTRUCTIONS ← 86-line system prompt (persona, tone, rules, format) ├─ IMPACT_TABLE ← 20 actions with CO2/water/waste lookup values ├─ PRODUCT_RECS ← static eco-product recs per material category ├─ INDIAN_CITIES ← 15 major Indian cities for recycling guide ├─ _get_model() ← lazy-init APIClient + ModelInference ( Granite 4 H Small ) ├─ get_eco_answer() ← multi-turn chat, builds [system]+messages list ├─ get_recycling_guide() ← single-turn recycling lookup call └─ compute_session_impact() ← aggregates logged actions → metric dict │ ▼ tools.py (Agent Tools) ├─ TOOLS ← 5 tool definitions (JSON Schema format) ├─ SCHEMES_DB ← 8 Indian government eco schemes ├─ execute_tool() ← routes tool calls to appropriate functions ├─ _execute_calculate_impact() ← reuse compute_session_impact() ├─ _execute_recycling_guide() ← reuse get_recycling_guide() ├─ _execute_web_search() ← DuckDuckGo search (free, no API key) + date header ├─ _execute_check_scheme() ← static lookup + web search fallback └─ _execute_analyze_household() ← LLM-powered personalized analysis │ ▼ agent.py (Agentic Loop) ├─ agent_loop() ← reason → act → observe → repeat (max 5 iterations) ├─ AGENT_SYSTEM_PROMPT ← tool usage rules + TODAY'S DATE injection + search trust rules ├─ _extract_tool_call() ← parses JSON tool calls from LLM response └─ format_tool_calls() ← formats tool usage for UI display │ ▼ app.py (Gradio Blocks — ultra-light theme) ├─ Tab 1: Chat ← chatbot + Agent Mode toggle + tool display + action chips ├─ Tab 2: Dashboard ← HTML metric cards from compute_session_impact() ├─ Tab 3: Recycling ← material+city dropdowns → get_recycling_guide() └─ Tab 4: Profile ← household form → profile_state (gr.State) ``` ## Agent Mode ### How It Works 1. User enables "Agent Mode" checkbox in Chat tab 2. User sends a message 3. Agent loop begins (max 5 iterations): - LLM receives message + tool definitions - LLM decides to call a tool (or gives final answer) - If tool call: execute tool, feed result back to LLM, repeat - If final answer: return response to user 4. Tool calls are displayed below the chatbot ### Available Tools | Tool | Purpose | When to Use | |------|---------|-------------| | `calculate_impact` | Get CO2/water/waste numbers | User asks about impact, wants numbers | | `get_recycling_guide` | City-specific recycling instructions | User asks how to recycle, where to dispose | | `web_search` | Search latest news, schemes, services | User asks about recent events, new policies | | `check_scheme` | Indian government scheme details | User asks about subsidies, government programs | | `analyze_household` | Personalized action plan | User wants comprehensive recommendations | ### Agent Loop Safety - **MAX_ITERATIONS = 5** — prevents infinite loops - **MAX_TOOL_CALLS_BEFORE_SYNTHESIS = 2** — forces LLM to answer after 2 tool calls - **TODAY'S DATE injection** — system prompt includes current date so LLM doesn't hallucinate outdated info - **Search result date header** — web search results include `Search conducted on: ` to reinforce recency - **Graceful degradation** — if tool fails, continues with error message - **Tool call logging** — all tool invocations are tracked and displayed ## Environment Variables | Variable | Source | Purpose | |---|---|---| | `WATSONX_API_KEY` | `.env.example` | IBM Cloud API key | | `WATSONX_PROJECT_ID` | watsonx.ai Studio | SDK project scope — required | | `WATSONX_URL` | `https://eu-de.ml.cloud.ibm.com` | eu-de watsonx.ai endpoint | ## Agentic AI Pattern This project uses **agentic AI** to transform IBM Granite into a domain-specific eco advisor with tool use: - **System Prompt:** 86-line `AGENT_INSTRUCTIONS` + tool usage instructions - **Tool Definitions:** 5 tools with JSON Schema parameters - **Agent Loop:** Multi-step reasoning with tool execution - **Static Knowledge:** `IMPACT_TABLE` (20 eco actions) and `PRODUCT_RECS` (8 material categories) - **Dynamic Context:** Household profile (members, location, habits) injected per session - **Tool Execution:** Real-time tool calls with result feedback - **Output Format:** Fixed 4-part structure (Quick Tip → Why it Matters → Impact → Optional Resource) - **Guardrails:** Never invent stats, label [Lookup] vs [Estimate], no medical/financial advice ## Prompt Engineering Pattern This project uses **prompt engineering** to transform IBM Granite into a domain-specific eco advisor: - **System Prompt:** 86-line `AGENT_INSTRUCTIONS` defining persona, output format, focus areas, and guardrails - **Static Knowledge:** `IMPACT_TABLE` (20 eco actions) and `PRODUCT_RECS` (8 material categories) injected via prompt - **Dynamic Context:** Household profile (members, location, habits) injected per session - **Output Format:** Fixed 4-part structure (Quick Tip → Why it Matters → Impact → Optional Resource) - **Guardrails:** Never invent stats, label [Lookup] vs [Estimate], no medical/financial advice ## UI Theme Ultra-light eco green theme: - Background: `#fcfcfd` (near white) - Primary accent: `#2e7d50` (green) - Cards: `#ffffff` with subtle shadows - Text: `#1c1c1e` (near black), muted: `#4a4a4e` - Borders: `#e4e4e7` (light gray) - CheckboxGroup styled as selectable pills/chips - Chatbot with welcome placeholder and white-flash prevention CSS ## Project Files | File | Purpose | |---|---| | `app.py` | Gradio Blocks UI — 4 tabs, callbacks, CSS theme | | `watsonx_client.py` | IBM watsonx.ai SDK wrapper, agent config, impact data | | `tools.py` | Agent tool definitions, executor, scheme database | | `agent.py` | Agentic loop with multi-step reasoning | | `requirements.txt` | Pinned Python dependencies (5 packages) | | `.env` | Local credentials (gitignored) | | `.env.example` | Template — safe to commit | | `AGENTS.md` | This file — agent guidance | | `README.md` | HF Spaces front-matter, setup instructions | | `ecoagent-plan.md` | Implementation plan and architecture decisions | | `architecture.png` | Architecture blueprint diagram | | `fill.txt` | PPT content fill for presentation | ## Deleted Files (v1 → v2) - `rag_pipeline.py` → replaced by `watsonx_client.py` - `ibm-credentials.env` → replaced by `.env` - `embed.txt` → was a debugging artifact; deleted