Spaces:
Sleeping
Sleeping
| # CLAUDE.md | |
| This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. | |
| ## What this is | |
| A Gradio web app: a **Medical Assistant** chat that runs a **background spiritual-distress classifier** on every patient message, plus a **verification/review workflow** so clinicians and chaplains can grade the classifier's output and export the results. Python 3.14, Gradio 6.1.0, LLM calls to Google Gemini and Anthropic Claude. | |
| ## Commands | |
| ```bash | |
| # Setup | |
| python3 -m venv .venv && source .venv/bin/activate | |
| pip install -r requirements.txt | |
| # .env must contain GEMINI_API_KEY and/or ANTHROPIC_API_KEY | |
| # Run β full interface (Chat, Verification, Model Settings, Edit Prompts, Profiles, Help) | |
| ./run.sh # port 7861, activates .venv and sets PYTHONPATH | |
| python app.py # port 7860 | |
| # Run β simplified interface (Chat, Conversation Verification, Help only) | |
| python run_simplified_interface.py | |
| # Tests | |
| python run_tests.py # all suites, one pytest subprocess per directory | |
| python -m pytest tests/unit -q # one suite | |
| python -m pytest tests/unit/test_consent_manager.py::test_name -q # one test | |
| ``` | |
| Tests import as `src.*`; pytest's rootdir insertion makes this work when run from the repo root. Run from anywhere else and you need `PYTHONPATH=.`. `direnv` (`.envrc`) does venv activation + `PYTHONPATH` + dotenv automatically. | |
| Baseline as of this writing: `tests/unit` is **5 failed, 170 passed** β the 5 failures in `test_enhanced_results_display.py` are pre-existing, not caused by your change. Verify against a clean checkout before assuming you broke something. Several older files under `tests/unit` and `tests/integration` are script-style (`test_*()` returning `bool`), so they pass in pytest regardless of what they print β don't trust them as regression gates. | |
| Env vars that change behavior: `LOG_PROMPTS=true` (dump every system/user prompt and response to `ai_interactions.log`), `PERF_TIMING` (per-stage `[PERF]` timing in the message path, on by default), `GRADIO_SERVER_PORT` / `GRADIO_SERVER_NAME` / `GRADIO_SHARE`, `GCP_SERVICE_ACCOUNT_B64` (base64 service-account JSON β enables Vertex AI instead of the Gemini API key). | |
| ## Two interfaces, one core | |
| `src/interface/gradio_app.py` (full) and `src/interface/simplified_gradio_app.py` (simplified, built for the testing team) are **separate, largely parallel UI builders over the same `SimplifiedMedicalApp` core**. A change to shared chat/verification behavior usually has to be made or checked in both. The full app delegates to the `*_handlers.py` modules; the simplified app uses `simplified_chat_handlers.py` and its own inline wiring. | |
| Entry points disagree on purpose: `app.py` β `gradio_app.main`, `run_simplified_interface.py` β `simplified_gradio_app.main`, and the README front-matter (`app_file:`) points Hugging Face Spaces at `simplified_gradio_app.py`. If you change what the deployed Space runs, update the README front-matter too. | |
| ## Message flow | |
| `SimplifiedMedicalApp.process_message` (`src/core/simplified_medical_app.py`) is the single entry point for every patient turn. It is a state machine over `SessionSpiritualState` (`spiritual_state.py`), *not* a straight classify-then-answer: | |
| 1. **Awaiting consent** β `_handle_consent_response` (patient is deciding on a chaplain referral). | |
| 2. **In triage** β `_handle_triage_response` β continues the existing YELLOW triage; the classifier is **not** re-run mid-triage. | |
| 3. **Otherwise** β `SpiritualMonitor.classify` returns GREEN / YELLOW / RED: | |
| - GREEN β normal medical reply. | |
| - YELLOW β `SoftTriageManager` asks up to 2β3 gentle clarifying questions, then resolves to GREEN or escalates to RED (`_resolve_to_green` / `_escalate_to_red`; forced decision at the question limit). | |
| - RED β crisis response + consent request + `ProviderSummaryGenerator` handoff summary. | |
| The response returned to Gradio is prefixed with a classification badge, and every exchange is written by `ConversationLogger` to `conversation_logs/session_*.json`. `spiritual_state.last_assessment` is the shared slot the display, the logger, and the verification tab all read β the triage/escalation helpers update it as a side effect. | |
| ## Agent name keys | |
| A small set of string keys threads through config, model overrides, prompt overrides, and the UI. They must stay in sync across four places: | |
| - `AGENT_CONFIGURATIONS` in `src/config/ai_providers_config.py` β provider + model + temperature per agent. | |
| - `apply_model_settings` in `src/interface/model_handlers.py` β the Model Settings tab writes `session.custom_models` under these keys. | |
| - `_prompt_name_to_agent` in `src/interface/prompt_handlers.py` β maps emoji UI labels ("π Spiritual Monitor (Classifier)") to agent keys. | |
| - `SimplifiedMedicalApp.set_model_overrides` / `set_prompt_overrides`, which propagate onto `AIClientManager`. | |
| `get_agent_config` **silently falls back to Gemini 2.5 Flash for an unknown agent name** β a typo'd key produces a working app that quietly uses the wrong model. Note that `SoftSpiritualTriage` and `TriageResponseEvaluator` are used by the UI but are not in `AGENT_CONFIGURATIONS`, so they currently hit that fallback. | |
| ## Prompt system | |
| Prompts are text files in `src/config/prompts/`, but resolution goes through `PromptController` (`src/config/prompt_management/prompt_controller.py`) with three tiers, highest first: | |
| 1. **Session override** β set from the Edit Prompts tab, scoped to one `session_id`, never touches disk. | |
| 2. **Centralized file** β `src/config/prompts/*.txt`, with shared components (indicators / rules / templates / categories from `prompt_management/data/*.json`) spliced into placeholders. | |
| 3. **Hardcoded default** β module-level `SYSTEM_PROMPT_*` constants in `spiritual_monitor.py`, `soft_triage_manager.py`, `src/config/prompts.py`. | |
| "Promote to File" writes a session override to the real `.txt` and leaves a `*.backup.<timestamp>.txt` beside it (that's what the existing backup files in `src/config/prompts/` are). `PromptController` caches per `agent_type + session_id`; if you edit a prompt file on disk while the app is running, the cache can serve the stale copy. | |
| ## Verification subsystems | |
| Two distinct workflows that share vocabulary but not code paths: | |
| - **Conversation Verification** β replays the *current chat session*, exchange by exchange, for reviewer grading. Handlers in `src/interface/verification_handlers.py` (`_generate_conv_verification*`, `_mark_conv_correct/_incorrect`, `_export_conv_records_to_{json,csv}`). State lives in Gradio component state, not in a store. The Provider Summary is appended as the **final exchange**, and on that step the classification flag is hidden (see Gradio notes below). | |
| - **Enhanced Verification** β batch testing via manual entry or CSV/XLSX upload (`enhanced_verification_interface.py`, `manual_input_interface.py`, `file_upload_interface.py`), persisted through `JSONVerificationStore` (`src/core/verification_store.py`) into `verification_sessions/`, exported to `verification_exports/`. | |
| Feature toggles for both live in `app_config.py` (`FEATURE_FLAGS`, `ENHANCED_VERIFICATION_CONFIG`). Standard Verification is deliberately disabled there β its functionality was folded into Enhanced Verification; leave it off unless asked. | |
| ## Gradio 6 gotchas this codebase has already been bitten by | |
| - A `gr.Radio` handed `""` raises (value not in choices) and fails the **entire** event response, painting "Error" across unrelated components. Normalize unselected radios to `None`. | |
| - Handler return arity must match the `outputs=` list on **every** branch, including early returns and empty-session paths. Mismatches surface as unrelated UI breakage, not a clear traceback. | |
| ## Conventions | |
| - Everything imports absolute from the repo root (`from src.core... import`); scripts that may be run directly re-insert the project root into `sys.path` at the top. | |
| - Property-based tests use Hypothesis and live in `tests/verification_mode/test_properties_*.py` and `tests/chaplain_feedback/test_properties_*.py` β these are the meaningful correctness gates. `manual_tests/` holds scripts that hit real APIs and are run by hand, never in CI. | |
| - Ignore `src/interface/enhanced_verification_ui_backup.py` β dead 1700-line copy kept around; don't edit it or use it as a reference. | |
| - `.gitignore` excludes `docs/`, `conversation_logs/`, `exports/`, `review/`, `verification_*/`, and (oddly) `src/core/verification_store.py` β that last one is already tracked so edits commit normally, but `git status` will not surface new files in those paths. | |
| - No PHI is persisted; API keys stay in `.env`. | |