diff --git a/README.md b/README.md index d18d0bd..978ba9a 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Meister-Eder -AI-powered conversational registration system for **Spielgruppe Pumuckl**, a playgroup run by Familienverein Fällanden (Fällanden, Switzerland). +AI-powered conversational registration agent for **Spielgruppe Pumuckl** (Familienverein Fällanden, Switzerland). Parents register their child and ask questions via email — the agent handles the conversation, validates all required fields, and notifies the playgroup admin on completion. Replaces a static Google Forms workflow with an AI agent that guides parents through child registration via natural conversation — over email or a web chat interface. @@ -19,20 +19,102 @@ Replaces a static Google Forms workflow with an AI agent that guides parents thr | Web chat | Real-time, session-based | | Email | Async, thread-tracked; reminders on days 3, 10, 25 | -## Status +## Prerequisites -Greenfield — specification complete, implementation not yet started. +- Python 3.13+ +- [uv](https://docs.astral.sh/uv/) (dependency manager) -## Running the Email Agent +## Installation -The email agent is a plain script invoked periodically via cron — no long-running daemon needed. - -### Scheduling with cron - -```cron -*/5 * * * * flock -n /tmp/meister-eder-email.lock python /path/to/check_email.py +```bash +git clone https://github.com/gurix/Meister-Eder.git +cd Meister-Eder +uv sync ``` -`flock -n` acquires an exclusive lock before running the script. If a previous run is still in progress when the next cron tick fires, the new invocation exits immediately (non-blocking). The lock is released automatically by the kernel when the process ends — even on crash — so stuck locks are not a concern. +## Configuration -Adjust `*/5` to whatever polling interval makes sense (e.g. `*/2` for every 2 minutes). \ No newline at end of file +Copy the example env file and fill in your values: + +```bash +cp .env.example .env +``` + +### Required variables + +| Variable | Description | +|---|---| +| `AI_MODEL` | litellm model string, e.g. `anthropic/claude-opus-4-6` or `openai/gpt-4o` | +| `ANTHROPIC_API_KEY` | API key for Anthropic models | +| `OPENAI_API_KEY` | API key for OpenAI models (if using OpenAI) | +| `IMAP_HOST` | IMAP server hostname for receiving parent emails | +| `IMAP_USERNAME` | Email account username | +| `IMAP_PASSWORD` | Email account password | +| `SMTP_HOST` | SMTP server hostname for sending replies | +| `REGISTRATION_EMAIL` | Sender address shown to parents | + +### Optional variables + +| Variable | Default | Description | +|---|---|---| +| `IMAP_PORT` | `993` | IMAP port | +| `IMAP_USE_SSL` | `true` | Use SSL for IMAP | +| `SMTP_PORT` | `587` | SMTP port | +| `SMTP_USE_TLS` | `true` | Use STARTTLS for SMTP | +| `DATA_DIR` | `data/` | Directory for conversation state and completed registrations | +| `KNOWLEDGE_BASE_DIR` | `openspec/…/knowledge-base` | Path to admin-editable knowledge base markdown files | +| `POLL_INTERVAL` | `60` | Seconds between inbox polls (only used when running as a daemon) | + +### Switching AI providers + +`AI_MODEL` uses [litellm](https://docs.litellm.ai/docs/providers) model strings — any supported provider works without code changes: + +```bash +# Anthropic (default) +AI_MODEL=anthropic/claude-opus-4-6 +ANTHROPIC_API_KEY=sk-ant-... + +# OpenAI +AI_MODEL=openai/gpt-4o +OPENAI_API_KEY=sk-... + +# Google Gemini +AI_MODEL=gemini/gemini-2.0-flash +GEMINI_API_KEY=... +``` + +## Running + +### As a cron job (recommended) + +The agent is a plain script — no long-running daemon needed. Schedule it with cron and use `flock` to prevent overlapping runs: + +```cron +*/5 * * * * flock -n /tmp/meister-eder-email.lock uv run python main.py +``` + +`flock -n` exits immediately if a previous run is still in progress, so the script is always safe to schedule aggressively. + +### Manually + +```bash +uv run python main.py +``` + +## Development + +### Running tests + +```bash +uv run pytest +``` + +All tests are unit tests — no network access or API keys required. + +### Knowledge base + +The agent answers parent questions from markdown files in the knowledge base directory. These files are designed to be edited directly by playgroup admins — no code changes needed to update fees, schedules, or policies. + +### Adding a new AI provider + +Set `AI_MODEL` to any [litellm-supported model string](https://docs.litellm.ai/docs/providers) and set the corresponding API key environment variable. No code changes required. diff --git a/src/agent/prompts.py b/src/agent/prompts.py index e834379..79f5003 100644 --- a/src/agent/prompts.py +++ b/src/agent/prompts.py @@ -13,7 +13,7 @@ STEP_DESCRIPTIONS = { "child_name": "Ask for the child's full name.", "child_dob": ( "Ask for the child's date of birth. " - "Validate age: indoor requires ≥2.5 years, outdoor requires ≥3 years." + "Validate age: indoor requires ≥2 years, outdoor requires ≥2.5 years." ), "playgroup_selection": ( "Explain both playgroup options and ask which the parent wants " @@ -152,7 +152,7 @@ def _build_registration_prompt(kb: KnowledgeBase, state: ConversationState) -> s ## Registration Flow (8 steps) 1. greeting — greet and detect intent 2. child_name — ask for child's full name -3. child_dob — ask for date of birth; validate age (indoor ≥2.5 yrs, outdoor ≥3 yrs) +3. child_dob — ask for date of birth; validate age (indoor ≥2 yrs, outdoor ≥2.5 yrs) 4. playgroup_selection — present options, collect type(s) and day(s) 5. special_needs — ask about special needs / allergies / medical conditions 6. parent_contact — name, street address, postal code, city, phone, email