DocUA Claude Opus 5 commited on
Commit
beb5a53
Β·
1 Parent(s): 09c4875

docs: add CLAUDE.md with architecture and workflow notes

Browse files

Covers what needs several files to piece together: the two parallel Gradio
apps over one core, the message-flow state machine, the agent-name keys that
must stay in sync across four files, the three-tier prompt resolution, the two
separate verification subsystems, and the Gradio 6 arity/Radio traps this repo
has already hit.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Files changed (1) hide show
  1. CLAUDE.md +96 -0
CLAUDE.md ADDED
@@ -0,0 +1,96 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+ ## What this is
6
+
7
+ 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.
8
+
9
+ ## Commands
10
+
11
+ ```bash
12
+ # Setup
13
+ python3 -m venv .venv && source .venv/bin/activate
14
+ pip install -r requirements.txt
15
+ # .env must contain GEMINI_API_KEY and/or ANTHROPIC_API_KEY
16
+
17
+ # Run β€” full interface (Chat, Verification, Model Settings, Edit Prompts, Profiles, Help)
18
+ ./run.sh # port 7861, activates .venv and sets PYTHONPATH
19
+ python app.py # port 7860
20
+
21
+ # Run β€” simplified interface (Chat, Conversation Verification, Help only)
22
+ python run_simplified_interface.py
23
+
24
+ # Tests
25
+ python run_tests.py # all suites, one pytest subprocess per directory
26
+ python -m pytest tests/unit -q # one suite
27
+ python -m pytest tests/unit/test_consent_manager.py::test_name -q # one test
28
+ ```
29
+
30
+ 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.
31
+
32
+ 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.
33
+
34
+ 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).
35
+
36
+ ## Two interfaces, one core
37
+
38
+ `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.
39
+
40
+ 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.
41
+
42
+ ## Message flow
43
+
44
+ `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:
45
+
46
+ 1. **Awaiting consent** β†’ `_handle_consent_response` (patient is deciding on a chaplain referral).
47
+ 2. **In triage** β†’ `_handle_triage_response` β€” continues the existing YELLOW triage; the classifier is **not** re-run mid-triage.
48
+ 3. **Otherwise** β†’ `SpiritualMonitor.classify` returns GREEN / YELLOW / RED:
49
+ - GREEN β†’ normal medical reply.
50
+ - 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).
51
+ - RED β†’ crisis response + consent request + `ProviderSummaryGenerator` handoff summary.
52
+
53
+ 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.
54
+
55
+ ## Agent name keys
56
+
57
+ A small set of string keys threads through config, model overrides, prompt overrides, and the UI. They must stay in sync across four places:
58
+
59
+ - `AGENT_CONFIGURATIONS` in `src/config/ai_providers_config.py` β€” provider + model + temperature per agent.
60
+ - `apply_model_settings` in `src/interface/model_handlers.py` β€” the Model Settings tab writes `session.custom_models` under these keys.
61
+ - `_prompt_name_to_agent` in `src/interface/prompt_handlers.py` β€” maps emoji UI labels ("πŸ” Spiritual Monitor (Classifier)") to agent keys.
62
+ - `SimplifiedMedicalApp.set_model_overrides` / `set_prompt_overrides`, which propagate onto `AIClientManager`.
63
+
64
+ `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.
65
+
66
+ ## Prompt system
67
+
68
+ 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:
69
+
70
+ 1. **Session override** β€” set from the Edit Prompts tab, scoped to one `session_id`, never touches disk.
71
+ 2. **Centralized file** β€” `src/config/prompts/*.txt`, with shared components (indicators / rules / templates / categories from `prompt_management/data/*.json`) spliced into placeholders.
72
+ 3. **Hardcoded default** β€” module-level `SYSTEM_PROMPT_*` constants in `spiritual_monitor.py`, `soft_triage_manager.py`, `src/config/prompts.py`.
73
+
74
+ "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.
75
+
76
+ ## Verification subsystems
77
+
78
+ Two distinct workflows that share vocabulary but not code paths:
79
+
80
+ - **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).
81
+ - **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/`.
82
+
83
+ 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.
84
+
85
+ ## Gradio 6 gotchas this codebase has already been bitten by
86
+
87
+ - 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`.
88
+ - 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.
89
+
90
+ ## Conventions
91
+
92
+ - 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.
93
+ - 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.
94
+ - Ignore `src/interface/enhanced_verification_ui_backup.py` β€” dead 1700-line copy kept around; don't edit it or use it as a reference.
95
+ - `.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.
96
+ - No PHI is persisted; API keys stay in `.env`.